/*
* 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 <e32math.h>
#include <f32file.h>

#include "sendebug.h"                 // internal Utils\inc - logging MACROs
#include "senlogger.h"
#include "senservicemanagerdefines.h" // internal Core\inc  - IPC enumerations

#include "rsenserviceconnection.h"

#include <SenSoapMessage.h>

#if defined (__WINS__) && !defined(EKA2)
static const TUint KServerMinHeapSize =    0x1000;     //  4K
static const TUint KServerMaxHeapSize =    0x100000;   // 1000K
#endif

static TInt StartServerL();
static TInt CreateServerProcessL();

CSenProgressResourceHandler::CSenProgressResourceHandler(TInt aTxnId,
        TBool aIncoming, TBool aIsSoap, TInt aProgress,
        RSenServiceConnection* aOwner): CActive(EPriorityStandard),
        iOwner(aOwner)
    {
    TTransferProgress& data = iProgressData();
    data.iTxnId = aTxnId;
    data.iIncoming = aIncoming;
    data.iSoap = aIsSoap;
    data.iProgress = aProgress;
    }

CSenProgressResourceHandler::~CSenProgressResourceHandler()
    {
    delete iSoapOrCid;
    }

void CSenProgressResourceHandler::DoCancel()
    {
    
    }

void CSenProgressResourceHandler::RunL()
    {
    iOwner->Remove(this);
    delete this;
    }

TInt CSenProgressResourceHandler::SetBuffer(const TDesC8& aSoapOrCid)
    {
    iSoapOrCid = aSoapOrCid.Alloc();
    if (iSoapOrCid)
        {
        return KErrNone;
        }
    return KErrNoMemory;
    }

CSenConnAgentSync::CSenConnAgentSync(): CActive(EPriorityStandard)
	{
	CActiveScheduler::Add(this);
	iStatus = KRequestPending;
	}

CSenConnAgentSync::~CSenConnAgentSync()
	{
	if(IsActive())
		{
		Cancel();
		}
	}

void CSenConnAgentSync::DoCancel()
	{	
	}

void CSenConnAgentSync::RunL()
	{
	}

void CSenConnAgentSync::Start()
	{
	SetActive();
	}

RSenServiceConnection::RSenServiceConnection(RFileLogger* aLog)
    : RSessionBase(),
      iMessageContextId(0),
      iLog(aLog)
    {
    // No implementation required
    }

void RSenServiceConnection::SetLog(RFileLogger* aLog)
    {
    iLog = aLog;
    }
void RSenServiceConnection::SetChannel(TInt aChannel)
{
     iTLSLogChannel=aChannel;
}

TInt RSenServiceConnection::Connect()
    {
    TInt error(KErrNone);
    TRAPD( leave, error = ::StartServerL(); )
    
    if( leave != KErrNone )
        {
        error = leave;
        }
        
    if( error == KErrNone )
        {
        error = CreateSession( KSenServiceManager, Version(), KDefaultMessageSlots );
        /// By defining TRequestStatus (last arg) to NULL, one could force 
        /// error = CreateSession( KSenServiceManager, Version(), KDefaultMessageSlots, NULL, NULL ); 
#ifdef _SENDEBUG
        if(error != KErrNone)
            {
            TLSLOG_FORMAT((KSenServiceConnectionLogChannel, KMinLogLevel , _L8("RSenServiceConnection::Connect - CreateSession returned error: (%d)"), error));
            }
        else
            {
            TLSLOG_L(KSenServiceConnectionLogChannel, KMinLogLevel,"RSenServiceConnection::Connect - CreateSession returned KErrNone");
            }
#endif // _SENDEBUG
        }
#ifdef _SENDEBUG
    else
        {
        TLSLOG_FORMAT((KSenServiceConnectionLogChannel, KMinLogLevel , _L8("RSenServiceConnection::Connect - StartServerL failed, error: (%d)"), error));
        }
#endif // _SENDEBUG
    return error;
    }

TVersion RSenServiceConnection::Version() const
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::Version");
    return(TVersion( KWsfServMajorVersionNumber, KWsfServMinorVersionNumber, KWsfServBuildVersionNumber) );
    }

void RSenServiceConnection::Initialize( TRequestStatus& aStatus,
                                        TDes8& aErrPtr,
                                        TDes& aSessionID,
                                        CSenChunk& aSenChunk,
                                        TInt aSdLength,
                                        TInt /* aCpLength */,
                                        TBool aHasAuthenticationCallback)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::Initialize");
    TIpcArgs args;
    args.Set(0, &aErrPtr);
    args.Set(1, &aSessionID);
    // Note: chunk will carry XML SD - and possibly consumer policy -
    // over the process boundary.
    aSenChunk.ChunkToArgs(args, 2);
    
    iFourInts().iInt1 = aSdLength;
    iFourInts().iInt2 = aHasAuthenticationCallback;
    args.Set(3,&iFourInts);
    
    SendReceive(ESenServInitialize, args, aStatus);
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::Initialize Completed");
    }


TInt RSenServiceConnection::IsReady(TBool& aReady)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::IsReady");
    TPtr8 descriptor(reinterpret_cast<TUint8*>(&aReady), sizeof(aReady), sizeof(aReady));
    TIpcArgs args;
    args.Set(0, &descriptor);
    return SendReceive(ESenServIsReady, args);
    }

TInt RSenServiceConnection::HasFacet(TDesC8& aUri, TBool& aHasFacet)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::HasFacet");
    TLSLOG_ALL(iTLSLogChannel, KMaxLogLevel,(aUri));
    TPtr8 descriptor(reinterpret_cast<TUint8*>(&aHasFacet), sizeof(aHasFacet), sizeof(aHasFacet));
    TInt length = aUri.Length();
    TIpcArgs args;
    args.Set(0, &aUri);
    args.Set(1, &descriptor);
    args.Set(2, length);
    return SendReceive(ESenServHasFacet, args);
    }

TInt RSenServiceConnection::CompleteServerMessagesOnOff(TBool& aOnOff)
    {
    TLSLOG(iTLSLogChannel, KMinLogLevel,(_L("RSenServiceConnection::CompleteServerMessagesOnOff")));

    // Note : Using TPtr8 since this is binary information
    TPtr8 descriptor(reinterpret_cast<TUint8*>(&aOnOff),sizeof(aOnOff),
        sizeof(aOnOff));

    TIpcArgs args;
    args.Set(0, &descriptor);

    return SendReceive(ESenServServerMessagesOnOff, args);
    }

void RSenServiceConnection::Transaction( TRequestStatus& aStatus,
                                         TDes8& aErrPtr,
                                         TDes8& aTxnPtr,
                                         CSenChunk& aClientOp )
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::Transaction");

    // Set the message context ID in here: it is only locally unique, inside each service connection - "in client scope"
    // Context IDs use negative range, to avoid collisions with txnIDs (which are always positive integers)
    aClientOp.ChunkHeader().SetContextId( --iMessageContextId );
    TLSLOG_FORMAT((iTLSLogChannel, KNormalLogLevel , _L8("Transaction - SetContextId: %d"), iMessageContextId));
    
    TIpcArgs args;
    args.Set(0, &aErrPtr);
    args.Set(1, &aTxnPtr);
    // This RChunk will pass message to server and include response when this
    // txn is complete
    aClientOp.ChunkToArgs(args,2);
    SendReceive(ESenServTransaction, args, aStatus);
    }

TInt RSenServiceConnection::SendMsgAndReceiveTxnId(CSenChunk& aClientOp)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::SendMsgAndReceiveTxnId");
    TInt retVal(KErrNone);

    TIpcArgs args;
    aClientOp.ChunkToArgs(args,0);
    args.Set(1,aClientOp.ChunkHeader().ContextId());
    retVal = SendReceive(ESenServSendMsgAndGetTxnId, args);

    return retVal;
    }
TInt RSenServiceConnection::MoveFile(CSenChunk& aClientOp,
                                     const TDesC8& aCid,
                                     RFile& aFile)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::SendFile");
    
    TInt retVal = aClientOp.DescToChunk(aCid,2);
    
    TIpcArgs args;

    if ( retVal == KErrNone)
        {
        aClientOp.ChunkToArgs(args,0);
        aFile.TransferToServer(args, 1, 2);
        
        retVal = SendReceive(ESenServMoveFile, args);
        }

    return retVal;
    }
    
TInt RSenServiceConnection::SendFileHandle(CSenChunk& aSenChunk, 
                      						RFile& aFile)
	{
  	 TInt retVal(KErrNone);
     TIpcArgs args;

     if ( retVal == KErrNone)
        {
         aSenChunk.ChunkToArgs(args,0);
         aFile.TransferToServer(args, 1, 2);       
         retVal = SendReceive(ESenServSendFileHandle, args);
        }

     return retVal;
	}

TInt RSenServiceConnection::MoveChunk(CSenChunk& aClientOp,
                                      const TDesC8& aCid,
                                      RChunk& aChunk,
                                      TInt aDataOffset,
                                      TInt aDataSize)
    {
    TLSLOG(iTLSLogChannel, KMinLogLevel,(_L("RSenServiceConnection::SendChunk")));
    
    TInt retVal = aClientOp.DescToChunk(aCid,2);
    
    TIpcArgs args;
    
    if ( retVal == KErrNone )
        {
        TIpcArgs args;
        aClientOp.ChunkToArgs(args,0);
        args.Set(1, aChunk);
        args.Set(2, aDataOffset);
        args.Set(3, aDataSize);
        retVal = SendReceive(ESenServMoveChunk, args);
        }

    return retVal;
    }

TInt RSenServiceConnection::RequestServiceDescription(TDes8& aSdLength)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RequestServiceDescription");
    TIpcArgs args;
    args.Set(0, &aSdLength);
    return SendReceive(ESenServRequestServiceDescription, args);
    }


TInt RSenServiceConnection::ReceiveServiceDescription(TDes8& aServiceDescription)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::ReceiveServiceDescription");
    TLSLOG_FORMAT((iTLSLogChannel, KNormalLogLevel , _L8("Waiting for SD: maxlength(%d):"),
                                aServiceDescription.MaxLength()));
    TIpcArgs args;
    args.Set(0, &aServiceDescription);
    return SendReceive(ESenServReceiveServiceDescription, args);
    }

TInt RSenServiceConnection::StartTransaction()
    {
    TLSLOG(iTLSLogChannel, KMinLogLevel,(_L("RSenServiceConnection::StartTransaction")));
    return SendReceive(ESenServStartTransaction);
    }

TInt RSenServiceConnection::TransactionCompleted()
    {
    TLSLOG(iTLSLogChannel, KMinLogLevel,(_L("RSenServiceConnection::TransactionCompleted")));
    return SendReceive(ESenServTransactionCompleted);
    }

TInt RSenServiceConnection::SetTransportPropertiesL(CSenChunk& aSenChunk)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::SetTransportPropertiesL");

    TIpcArgs args;
    aSenChunk.ChunkToArgs(args, 0);

    TInt retVal = SendReceive(ESenServSetTransportProperties, args);
    
    return retVal;
    }

TInt RSenServiceConnection::TransportPropertiesL(CSenChunk& aSenChunk)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::TransportPropertiesL");

    TIpcArgs args;
    aSenChunk.ChunkToArgs(args, 0);

    TInt retVal = SendReceive(ESenServTransportProperties, args);
    
    return retVal;
    }

void  RSenServiceConnection::CancelSession(TRequestStatus& aStatus)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::CancelSession(sync)");
    SendReceive(ESenServCancelSession, aStatus);
    }

// ASYNC VERSION
void RSenServiceConnection::CancelRequests(TRequestStatus& aStatus)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::CancelSession(async)");
    TIpcArgs args; // empty
    SendReceive(ESenServCancelSession, args, aStatus);
    }

void RSenServiceConnection::CancelRequest(TInt aTransactionID)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::CancelRequest");
    TIpcArgs args;
    args.Set(0, aTransactionID);
    SendReceive(ESenServCancelRequest, args);
    }

void RSenServiceConnection::DataTrafficDetails(TSenDataTrafficDetails& aDetails,
											   TSenDataTrafficOperations& aOperations) 
	{
	TLSLOG_L(iTLSLogChannel, KSenServiceConnectionLogLevel,"RSenServiceConnection::DataTrafficDetails");
    TPtr8 trafficDetailsDesc(reinterpret_cast<TUint8*>(&aDetails),sizeof(aDetails),
        					sizeof(aDetails));
    TIpcArgs args;
    args.Set(0,&trafficDetailsDesc);
    args.Set(1,&aOperations.iReset);
    SendReceive(ESenTrafficDetails, args);
    }

TInt RSenServiceConnection::ConnectionID()
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::ConnectionID");
    TInt connectionID = SendReceive( ESenServConnectionID );
    //LOG_WRITEFORMAT((_L("- Connection ID: (%d)"), connectionID));
    return connectionID;
    }

TInt RSenServiceConnection::IdentityProviderL(CSenChunk& aSenChunk)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::IdentityProviderL");

    TIpcArgs args;
    aSenChunk.ChunkToArgs(args, 0);

    TInt retVal = SendReceive(ESenServConnectionIdentityProvider, args);
    
    return retVal;
    }
    
TInt RSenServiceConnection::RegisterIdentityProvider(TDesC8& aMessage)
    {
#ifdef _SENDEBUG
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RegisterIdentityProvider");

    TPtrC8 outBufferLeft = aMessage.Left(30);
    TLSLOG_FORMAT((iTLSLogChannel, KNormalLogLevel , _L8("Out: %S ..., length: (%d)"), &outBufferLeft,
        aMessage.Length()));
#endif // _SENDEBUG

    TInt length = aMessage.Length();

    TIpcArgs args;
    args.Set(0, &aMessage);
    args.Set(1, length);

    return SendReceive(ESenServRegisterIdentityProvider, args);
    }
	
TInt RSenServiceConnection::RegisterTransferObserver(
        const TDesC* aServerName, TAny* aConnection)
    {
    TInt retVal(KErrNone);
    CActiveSchedulerWait asWait;
    TIpcArgs args(aServerName, aConnection, &asWait);
    CSenConnAgentSync* caSync = new CSenConnAgentSync();
    if(caSync)
    	{
	    SendReceive(ESenObserveTransfer, args, caSync->iStatus);
	    caSync->Start();
	    Mem::FillZ(&asWait, sizeof(asWait));
	    asWait.Start();
	    retVal = caSync->iStatus.Int();
	    delete caSync;
    	}
    else
    	{
    	retVal = KErrNoMemory;
    	}
    return retVal;
    }

TInt RSenServiceConnection::SendFileProgress( TInt aTxnId, 
                                              TBool aIncoming,
                                              TBool aIsSoap, 
                                              const TDesC8& aSoapOrCid, 
                                              TInt aProgress)
    {
    CSenProgressResourceHandler* resHandler = new CSenProgressResourceHandler(
            aTxnId, aIncoming, aIsSoap, aProgress, this);
    if (!resHandler)
        {
        return KErrNoMemory; // new (ELeave) was not used!
        }
    TInt retVal = resHandler->SetBuffer(aSoapOrCid);
    if ( retVal != KErrNone)
        {
        delete resHandler;
        }
    else
        {
        if (iFirst)
            {
            iFirst->iPrevious = resHandler;
            }
        resHandler->iNext = iFirst;
        iFirst = resHandler;

        CActiveScheduler::Add(resHandler);
        resHandler->SetActive();
        resHandler->iStatus = KRequestPending;

        TIpcArgs args(&resHandler->iProgressData, resHandler->iSoapOrCid);
        SendReceive(ESenTransferProgress, args, resHandler->iStatus);
        }
    return retVal;
    }

void RSenServiceConnection::Remove(
        CSenProgressResourceHandler* aResourceHandler)
    {
    if (aResourceHandler == iFirst)
        {
        iFirst = aResourceHandler->iNext;
        if (iFirst)
            {
            iFirst->iPrevious = NULL;
            }
        }
    else
        {
        aResourceHandler->iPrevious->iNext = aResourceHandler->iNext;
        }
    }


void RSenServiceConnection::Close()
    {
    CSenProgressResourceHandler* resHandler = iFirst;
    while (resHandler)
        {
        resHandler->Cancel();
        CSenProgressResourceHandler* tmp = resHandler;
        resHandler = resHandler->iNext;
        delete tmp;
        }
    RSessionBase::Close();
    }

TInt RSenServiceConnection::SearchIdentityProviderL(CSenChunk& aSenChunk, const TDesC8& aProviderId)
	{
	TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::SearchIdentityProviderL");
	
	TInt length = aProviderId.Length();
	
	TIpcArgs args;
    aSenChunk.ChunkToArgs(args, 0);
    args.Set(1, &aProviderId);
    args.Set(2, length);
  
    TInt retVal = SendReceive(ESenServSearchIdentityProvider, args);
    return retVal;
	}

TInt RSenServiceConnection::RegisterAuthenticationObserver(const TDesC* aServerName, TAny* aConnection)
	{
	TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RegisterAuthenticationObserver");
	CActiveSchedulerWait asWait;
    TIpcArgs args(aServerName, aConnection, &asWait);
    TRequestStatus rs = KRequestPending;
    SendReceive(ESenObserveAuthCallback, args, rs);
    Mem::FillZ(&asWait, sizeof(asWait));
    asWait.Start();
    User::WaitForRequest(rs);
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RegisterAuthenticationObserver Completed");
    return rs.Int();
	}

TInt RSenServiceConnection::RegisterCoBrandingObserver(
        const TDesC* aServerName, TAny* aConnection)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RegisterCoBrandingObserver");
	CActiveSchedulerWait asWait;
    TIpcArgs args(aServerName, aConnection, &asWait);
    TRequestStatus rs = KRequestPending;
    SendReceive(ESenObserveCoBranding, args, rs);
    Mem::FillZ(&asWait, sizeof(asWait));
    asWait.Start();
    User::WaitForRequest(rs);
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RegisterCoBrandingObserver Completed");
    return rs.Int();
    }
#ifdef __ENABLE_ALR__
TInt RSenServiceConnection::RegisterMobilityObserverL(
        const TDesC* aServerName, TAny* aConnection)
    {
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RegisterMobilityObserverL");
    TInt retVal(KErrNone);
    CActiveSchedulerWait asWait;
    TIpcArgs args(aServerName, aConnection, &asWait);
    CSenConnAgentSync* caSync = new CSenConnAgentSync();
    if(caSync)
    	{
	    SendReceive(ESenServRegisterMobiltyObserver, args, caSync->iStatus);
	    caSync->Start();
	    Mem::FillZ(&asWait, sizeof(asWait));
	    asWait.Start();
	    retVal = caSync->iStatus.Int();
	    delete caSync;
    	}
    else
    	{
    	retVal = KErrNoMemory;
    	}
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::RegisterMobilityObserverL Completed");
    return retVal;
    }


TInt RSenServiceConnection::MigrateToPrefferedCarrierL(TBool &aUserChoice)
	{
	TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::MigrateToPrefferedCarrierL");
	
	 // Note : Using TPtr8 since this is binary information
	TPtr8 descriptor(reinterpret_cast<TUint8*>(&aUserChoice),sizeof(aUserChoice),
        sizeof(aUserChoice));

    TInt retVal(KErrNone);
    TIpcArgs args(&descriptor) ; 
    
    CSenConnAgentSync* caSync = new CSenConnAgentSync();
    if(caSync)
    	{
        caSync->Start();    	
	    SendReceive(ESenServMigrateToPreffredCarrier, args, caSync->iStatus);
	    retVal = caSync->iStatus.Int();
	    delete caSync;
    	}
    else
    	{
    	retVal = KErrNoMemory;
    	}
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::MigrateToPrefferedCarrierL Completed");
    return retVal;
	    
	}	

TInt RSenServiceConnection::NewCarrierAcceptedL(TBool &aUserChoice)
	{
	TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::MigrateToPrefferedCarrierL");
	
	 // Note : Using TPtr8 since this is binary information
	 TPtr8 descriptor(reinterpret_cast<TUint8*>(&aUserChoice),sizeof(aUserChoice),
        sizeof(aUserChoice));

    TInt retVal(KErrNone);
    TIpcArgs args(&descriptor) ;
    CSenConnAgentSync* caSync = new CSenConnAgentSync();
    if(caSync)
    	{
        caSync->Start();    	
	    SendReceive(ESenServNewCarrierAccepted, args, caSync->iStatus);
	    retVal = caSync->iStatus.Int();
	    delete caSync;
    	}
    else
    	{
    	retVal = KErrNoMemory;
    	}
    TLSLOG_L(iTLSLogChannel, KMinLogLevel,"RSenServiceConnection::MigrateToPrefferedCarrierL Completed");
    return retVal;	    
	}	
#endif

RFileLogger* RSenServiceConnection::Log() const
    {
    return iLog;
    }

static TInt StartServerL()
    {
    TInt result(KErrNotFound);

#ifdef _SENDEBUG   
    RFileLogger log;
    CleanupClosePushL(log);
    User::LeaveIfError( log.Connect() );
    log.CreateLog( KSenServiceConnectionLogDir, _L("SenStartServer.log"), EFileLoggingModeAppend );
    log.Write(_L("- StartServerL() - invoked by SC."));
#endif // _SENDEBUG

    TFindServer findSenServiceManager(KSenServiceManager);
    TFullName name;

    result = findSenServiceManager.Next(name);
    if (result == KErrNone)
        {
        // Server already running
#ifdef _SENDEBUG        
        log.Write(_L8("- Server already running, KErrNone"));
        log.CloseLog();
        CleanupStack::PopAndDestroy(); // log.Close()
#endif // _SENDEBUG        
        return KErrNone;
        }

    RSemaphore semaphore;
    CleanupClosePushL(semaphore);

    // First, try to open the semaphore (if someone else created it already):
    result = semaphore.OpenGlobal( KSenServiceManagerSemaphoreName );
    if( result == KErrNone )
        {
        // If another client is starting up SEN.EXE, this client should return
        // to re-connect loop (wait one sec, max 5 times)
#ifdef _SENDEBUG        
        log.Write(_L8("- OpenGlobal OK => Another client already starting up SEN.EXE. About to WAIT and RE-CONNECT."));
#endif        
        result = KErrServerBusy;
        }
    else // could not find any already opened global semaphore ==> it is safe to create new one
        {   
        // Semaphore has not yet been created, so instantiate it now(!)
        result = semaphore.CreateGlobal( KSenServiceManagerSemaphoreName, 0 );
#ifdef _SENDEBUG        
        if( result != KErrNone )
            {
            log.Write(_L8("CreateGlobal failed"));
            log.WriteFormat(_L8("- error: %d"), result);
            }
#endif        
        }
        
    if (result != KErrNone)
        {
        CleanupStack::PopAndDestroy(); // semaphore.Close()
#ifdef _SENDEBUG        
        log.CloseLog();
#endif // _SENDEBUG        
        if( result != KErrServerBusy )
            {
#ifdef _SENDEBUG        
            log.Write(_L8("- CreateGlobal failed => Another client already starting up SEN.EXE. About to WAIT and RE-CONNECT."));
            CleanupStack::PopAndDestroy(); // log.Close()
#endif // _SENDEBUG        
            result = KErrServerBusy; // again, this error will activate re-connect loop (max 5 times)
            }
        return result;
        }

    result = CreateServerProcessL();
    if (result != KErrNone)
        {
        CleanupStack::PopAndDestroy(); // semaphore.Close()
#ifdef _SENDEBUG        
        log.Write(_L8("CreateServerProcessL failed"));
        log.CloseLog();
        CleanupStack::PopAndDestroy(); // log.Close()
#endif // _SENDEBUG         
        return result;
        }

    // Now start waiting for signal from server: it will release this semaphore from wait:
    semaphore.Wait();  
    CleanupStack::PopAndDestroy(); // semaphore.Close()
    
#ifdef _SENDEBUG        
    log.Write(_L("Log file closed."));
    log.CloseLog();
    CleanupStack::PopAndDestroy(); // log.Close()    
#endif // _SENDEBUG
    return  KErrNone;
    }

static TInt CreateServerProcessL()
    {
    TInt result(KErrNone);

#ifdef _SENDEBUG
    RFileLogger log;
    CleanupClosePushL(log);
    User::LeaveIfError( log.Connect() );
    // Note: appends to the log created in StartServer(), as it already exists
    log.CreateLog( KSenServiceConnectionLogDir, _L("SenStartServer.log"), EFileLoggingModeAppend );
    log.Write(_L("- CreateServerProcessL() - invoked by SC."));
#endif //_SENDEBUG

    const TUidType serverUid(KNullUid, KNullUid, KServerUid3);

#if defined( __WINS__ ) && !defined(EKA2)
    // WINDOWS emulator version
    RLibrary lib;
    CleanupClosePushL(lib);

    RThread server;
    CleanupClosePushL(server);

    result = lib.Load( KSenServiceManagerFileName, serverUid );

    if(result==KErrNone)
        {
#ifdef _SENDEBUG
        log.Write(_L8("Library successfully loaded, KErrNone"));
#endif // _SENDEBUG
        
        //  Get the WinsMain function
        TLibraryFunction functionWinsMain = lib.Lookup(1);

        //  Call it and cast the result to a thread function
        TThreadFunction serverThreadFunction =
            reinterpret_cast<TThreadFunction>(functionWinsMain());

        TName threadName(KSenServiceManagerFileName);

        // Append a random number to make it unique
        threadName.AppendNum(Math::Random(), EHex);

        result = server.Create(threadName,   // create new server thread
                               serverThreadFunction, // thread's main function
                               KDefaultStackSize,
                               NULL,
                               &lib,
                               NULL,
                               KServerMinHeapSize,
                               KServerMaxHeapSize,
                               EOwnerProcess);

        // if successful, server thread now has the handle to library:

        if(result== KErrNone)
            {
            server.SetPriority(EPriorityMore);
            }
        }
#ifdef _SENDEBUG
    else
        {
        log.Write(_L8("- Could not load library"));
        }
#endif // _SENDEBUG

    CleanupStack::Pop(); // server (thread)
    CleanupStack::PopAndDestroy(); // lib
    CleanupClosePushL(server);

#else // _WINS_ not defined (EKA2, for example)
    RProcess server;
    CleanupClosePushL(server);
    result = server.Create( KSenServiceManagerFileName, _L(""), serverUid );
#endif // _WINS_

    if( result == KErrNone )
        {
#ifdef _SENDEBUG
        log.Write( _L8("- Server successfully created (KErrNone)") );
#endif // _SENDEBUG
        server.Resume();
        }
#ifdef _SENDEBUG
    else
        {
        log.Write( _L8("- Could not create server") );
        }
#endif // _SENDEBUG

    CleanupStack::PopAndDestroy(); // server.Close();

#ifdef _SENDEBUG
    CleanupStack::PopAndDestroy(); // log.Close();
#endif // _SENDEBUG

    return result;
    }
    

// End of file



