// Copyright (c) 2001-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:
// $Workfile: btsendop.cpp $
// $Author: Stevep $
// $Revision: 10 $
// $Date: 25/03/02 9:32 $
// 
//

//class include
#include "btsendop.h"

//system includes
#include <btmsgtypeuid.h>	//KUidMsgTypeBt
#include "btmtmcmds.h"	//EBtMtmCmdSend
//#include <bttypes.h>

//user includes
//#include "btcmtm.h"	//EBtcCmdSend
//#include "btmsgtypeuid.h" //KUidMsgTypeBt

const TInt KPacketBufferSize=20000; // Packet buffer size

CBtServerSendOperation* CBtServerSendOperation::NewL(CMsvServerEntry& aSendObj,	const TObexBluetoothProtocolInfo& aBtProtocolInfo, TInt aConnectTimeoutMicroSeconds, TInt aPutTimeoutMicroseconds, const TDesC* aConnectPassword, TRequestStatus& aObserverRequestStatus)
/**
 * Second phase constructor.
 *
 * @param aSendObj Reference to the object to send.
 * @param aBtProtocolInfo Protocol info to initialise the CObexCleint
 * @param aConnectTimeoutMicroSeconds Timeout period for Connect operation in microseconds.
 * @param aPutTimeoutMicroseconds Timeout period for Put operation in microseconds.
 * @param aConnectPassword Pointer to the password for Bluetooth validation.
 * @param aObserverRequestStatus Canonical TRequestStatus for control of active object.
 * @leave KErrXXX System-wide error codes
 */
	{
	CBtServerSendOperation* self=new(ELeave) CBtServerSendOperation(aSendObj, aBtProtocolInfo, aConnectTimeoutMicroSeconds, aPutTimeoutMicroseconds, aObserverRequestStatus);
	CleanupStack::PushL(self);
	self->ConstructL(aConnectPassword);
	CleanupStack::Pop(); //self
	return self;
	}

CBtServerSendOperation::CBtServerSendOperation(CMsvServerEntry& aSendObj, const TObexBluetoothProtocolInfo& aBtProtocolInfo, TInt aConnectTimeoutMicroSeconds, TInt aPutTimeoutMicroSeconds, TRequestStatus& aObserverRequestStatus)
	:CObexServerSendOperation(KUidMsgTypeBt, aSendObj, aConnectTimeoutMicroSeconds, aPutTimeoutMicroSeconds, aObserverRequestStatus),
		iBtProtocolInfo(aBtProtocolInfo),iBTObexPortNumber(0)	//default bitwise copy constructor should suffice
/**
 * Constructor.
 *
 * @param aSendObj Reference to the object to send.
 * @param aBtProtocolInfo Protocol info to initialise the CObexCleint
 * @param aConnectTimeoutMicroSeconds Timeout period for Connect operation in microseconds.
 * @param aPutTimeoutMicroseconds Timeout period for Put operation in microseconds.
 * @param aConnectPassword Pointer to the password for Bluetooth validation.
 * @param aTargetID Unsigned Int32 containing target ID if present.
 * @param aSendTargetID TBool for flag to send target ID or not.
 * @param aObserverRequestStatus Canonical TRequestStatus for control of active object.
 */
	{
	}

CBtServerSendOperation::~CBtServerSendOperation()
	{
	delete iSdpUtils;

	iLinkAdapter.Close();
	iSocketServ.Close();
	}

void CBtServerSendOperation::InitialiseObexClientL()
/**
 * Initialises the Obex client to use Bluetooth as the transport mechanism with the parameters as specified in the
 * constructor.
 *
 * @leave KErrXXX System-wide error codes 
 */

	{
	//Prevent the link from going into low power modes before the SDP query takes place. 
	PreventLowPowerModes(); 
	
	// trigger SDP Lookup
	iSdpUtils = CObexSdpUtils::NewL(*this);
	
	User::LeaveIfError(iSdpUtils != NULL);

	TBTDevAddr devAddr = iBtProtocolInfo.iAddr.BTAddr();
	iSdpUtils->RemoteBtObexQueryL(devAddr);

	// tell the obex server module we're async
	iAsyncInit = ETrue;
	}




void CBtServerSendOperation::RemoteBtObexQueryResult(TInt aError, TInt aPortNumber, TBool /*aObexObjectPushProfileSupported*/, 
									 TInt /*aObexObjectPushProfileVersion*/, TObexSupportedFormatsList /*aSupportedFormats*/)
	/**
	 * SDP Query result, parameters have the following meaning:
	 *
	 * @param aError If this is anything but KErrNone then the query has not completed correctly and all other parameters are meaningless.
	 * @param aPortNumber - The RFCOMM port number that the remote device supports OBEX on
	 * @param aObexObjectPushProfileSupported - ETrue if the remote device supports the Bluetooth OBEX Push Profile
	 * @param aObexObjectPushProfileVersion - Version of Bluetooth OBEX Push Profile supported (only valid if aObexObjectPushProfileSupported == ETrue)
	 * @param aSupportedFormats - Structure containing a list of the OBEX Object formats supported by the remote device
	 */
	{

	if(aError)
		{
		// finish the async init at this point
		TRequestStatus* status = &iStatus;
		User::RequestComplete(status, aError);
		}
	else
		{
		// remember the port number
		iBTObexPortNumber = aPortNumber;

		// finish the async init at this point
		TRequestStatus* status = &iStatus;
		User::RequestComplete(status, KErrNone);
		}
	}

void CBtServerSendOperation::SecondPhaseObexClientInitL()
/**
 * Fills in the iBtProtocolInfo structure with the results of the SDP Lookup.
 */
	{
	delete iSdpUtils;
	iSdpUtils = NULL;

	// use the port number to complete initialisation
	TRfcommSockAddr& sockAddr = iBtProtocolInfo.iAddr;
	sockAddr.SetPort(iBTObexPortNumber);

	// setting of receive & transmit packet buffer size.
	TObexProtocolPolicy obexProtocolPolicy;
	obexProtocolPolicy.SetReceiveMtu(KPacketBufferSize);
	obexProtocolPolicy.SetTransmitMtu(KPacketBufferSize);

	// Initialise Obex client object.
	iObexClient = CObexClient::NewL(iBtProtocolInfo,obexProtocolPolicy); 
	}

void CBtServerSendOperation::PreConnectOperations()
	{
	}

void CBtServerSendOperation::PostConnectOperations()
	{
	// If the connection attempt has failed and we are not going to retry the connection,
	// make sure that the link is allowed to go into low power modes.

	const TDesC8* progressDes;
 	TRAPD(error, progressDes = &ProgressL());

	if (error == KErrNone)
		{
		TPckgBuf<TObexMtmProgress> package;
		package.Copy(*progressDes);

		if (package().iSendState == TObexMtmProgress::ESendError)
			{
			AllowLowPowerModes();
			}
		}
	}

void CBtServerSendOperation::PreSendOperations()
	{
	// Try to ensure the link does not go into a low power mode.
	// Note that we may already be preventing low power modes as a result of attempting
	// to do this prior to the connection setup. In this case, calling it again does
	// nothing.
	// Note that as the obex connection is setup, this should not fail. If for some reason
	// it does, this would result in a slower file transfer.
	PreventLowPowerModes();
	}

void CBtServerSendOperation::PostSendOperations()
	{
	// Allow the link to go into low power modes
	AllowLowPowerModes();
	}

void CBtServerSendOperation::DoCancel()
	{
	// As the transfer is being cancelled, allow the link to go into low power modes
	AllowLowPowerModes();

	delete iSdpUtils;
	iSdpUtils = NULL;

	CObexServerSendOperation::DoCancel();
	}

void CBtServerSendOperation::AllowLowPowerModes()
	{
	// Allow the link to go into low power modes
	if (iPreventingLowPowerModes)
		{
		iLinkAdapter.AllowLowPowerModes(EAnyLowPowerMode);
		iPreventingLowPowerModes = EFalse;
		}

	iLinkAdapter.Close();
	iSocketServ.Close();
	}

void CBtServerSendOperation::PreventLowPowerModes()
	{
	// Prevent the link from going into low power modes. This means the connect and send
	// operations will be much quicker.

	if (iPreventingLowPowerModes)
		{
		return;
		}

	// Connect to the socket server
	if (!iSocketServ.Handle())
		{
		if (iSocketServ.Connect() != KErrNone)
			{
			return;
			}
		}

	// Open the bluetooth link adapter
	if (!iLinkAdapter.IsOpen())
		{
		TBTDevAddr devAddr = iBtProtocolInfo.iAddr.BTAddr();
			
		if (iLinkAdapter.Open(iSocketServ, devAddr) != KErrNone)
			{
			return;
			}
		}

	if (iLinkAdapter.PreventLowPowerModes(EAnyLowPowerMode) == KErrNone)
		{
		iPreventingLowPowerModes = ETrue;
		}
	}
