Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// btincoming.cpp
//
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <e32base.h>
#include "btincomingserial.h"
#include "btservice.h"
#include "btdebug.h"
_LIT(KBtSerialPanic, "BTSerial");
void Panic(TBtSerialPanic aReason)
{
TRACE2("BtIncoming panic %d", aReason);
User::Panic(KBtSerialPanic, aReason);
};
NONSHARABLE_CLASS(CBtRegQuery) : public CActive
{
public:
CBtRegQuery(CBluetoothIncomingSerialConnection& aOwner);
void Start(CBTRegistryResponse& aResponse);
private:
virtual void RunL();
virtual void DoCancel();
private:
CBluetoothIncomingSerialConnection& iOwner;
CBTRegistryResponse* iResponse;
};
EXPORT_C CBluetoothIncomingSerialConnection* CBluetoothIncomingSerialConnection::NewL(MBtIncomingConnectionObserver& aObserver)
{
TRACE1("CBluetoothIncomingSerialConnection::NewL");
CBluetoothIncomingSerialConnection* self = new(ELeave)CBluetoothIncomingSerialConnection(aObserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
EXPORT_C CBluetoothIncomingSerialConnection::~CBluetoothIncomingSerialConnection()
{
TRACE1("CBluetoothIncomingSerialConnection::~CBluetoothIncomingSerialConnection");
delete iService;
delete iSocket;
iSockServ.Close();
iSdpSession.Close();
}
CBluetoothIncomingSerialConnection::CBluetoothIncomingSerialConnection(MBtIncomingConnectionObserver& aObserver)
: iObserver(aObserver)
{
}
void CBluetoothIncomingSerialConnection::ConstructL()
{
TRACE1("+CBluetoothIncomingSerialConnection::ConstructL");
User::LeaveIfError(iSdpSession.Connect());
User::LeaveIfError(iSockServ.Connect());
TUUID serialPortUUID = TUUID(0x1101);
iService = CBtService::NewL(serialPortUUID, iSdpSession, iSockServ, *this, KRFCOMM);
// create a blank socket for the incoming connection
iSocket = CBluetoothSocket::NewL(*this, iSockServ);
TRACE1("-CBluetoothIncomingSerialConnection::ConstructL");
}
EXPORT_C void CBluetoothIncomingSerialConnection::WaitForConnection()
{
TRACE1("CBluetoothIncomingSerialConnection::WaitForConnection");
iService->AcceptConnection(*iSocket);
}
EXPORT_C TBool CBluetoothIncomingSerialConnection::Connected()
{
TRACE2("CBluetoothIncomingSerialConnection::Connected %d", iSocketReady);
return iSocketReady;
}
EXPORT_C TBTDevAddr CBluetoothIncomingSerialConnection::ConnectedDeviceAddrL()
{
if (!iSocketReady) User::Leave(KErrNotReady);
TBTSockAddr remote;
iSocket->RemoteName(remote);
return remote.BTAddr();
}
EXPORT_C void CBluetoothIncomingSerialConnection::GetConnectedDeviceNameL()
{
if (iConnectedDevice) return;
if (!iSocketReady) User::Leave(KErrNotReady);
// lazy construction....
if (!iRegQuery) iRegQuery = new(ELeave)CBtRegQuery(*this);
if (iRegQuery->IsActive())
{
return;
}
if (reinterpret_cast<RHandleBase&>(iBtRegServ).Handle() == KNullHandle)
{
User::LeaveIfError(iBtRegServ.Connect());
}
if (iBtReg.SubSessionHandle() == KNullHandle)
{
User::LeaveIfError(iBtReg.Open(iBtRegServ));
}
if (!iRegReponse) iRegReponse = CBTRegistryResponse::NewL(iBtReg);
TBTSockAddr remote;
iSocket->RemoteName(remote);
TBTRegistrySearch findConnected;
findConnected.FindAddress(remote.BTAddr());
TRequestStatus stat;
iBtReg.CreateView(findConnected, stat);
User::WaitForRequest(stat);
User::LeaveIfError(stat.Int());
iRegQuery->Start(*iRegReponse);
}
void CBluetoothIncomingSerialConnection::QueryComplete(TInt aError)
{
iBtReg.CloseView();
if (aError == KErrNone)
{
RBTDeviceArray& results = iRegReponse->Results();
if (results.Count() != 1)
// we queried by BD address, so should get 1 (or 0) results
{
aError = KErrNotFound;
}
if (aError == KErrNone)
{
TRAP(aError, iConnectedDevice = results[0]->CopyL());
}
if (aError == KErrNone)
{
if (iConnectedDevice->IsValidFriendlyName())
{
aError = iDeviceName.Create(iConnectedDevice->FriendlyName());
}
else
{
aError = iDeviceName.Create(iConnectedDevice->DeviceName().Length());
if (aError == KErrNone)
{
iDeviceName.Copy(iConnectedDevice->DeviceName());
}
}
if (aError!=KErrNone)
{
delete iConnectedDevice;
iConnectedDevice = NULL;
}
}
}
iObserver.BtNameReceived(aError, iDeviceName);
}
EXPORT_C void CBluetoothIncomingSerialConnection::Write(const TDesC8& aData)
{
TRACE1("CBluetoothIncomingSerialConnection::Write");
__ASSERT_ALWAYS(iSocketReady, Panic(EBtSerialNotConnected));
__ASSERT_ALWAYS(!iSending, Panic(EBtSerialWritePending));
TInt err = iSocket->Send(aData, 0);
if (err==KErrNone)
{
iSending = ETrue;
}
else
{
iObserver.BtWriteComplete(err);
}
}
EXPORT_C void CBluetoothIncomingSerialConnection::CancelWrite()
{
TRACE1("CBluetoothIncomingSerialConnection::CancelWrite");
iSocket->CancelSend();
iSending = EFalse;
}
EXPORT_C void CBluetoothIncomingSerialConnection::Read(TDes8& aData)
{
TRACE1("CBluetoothIncomingSerialConnection::Read");
__ASSERT_ALWAYS(iSocketReady, Panic(EBtSerialNotConnected));
__ASSERT_ALWAYS(!iReceiving, Panic(EBtSerialReadPending));
aData.Zero();
TInt err = iSocket->RecvOneOrMore(aData, 0, iXferLen);
if (err==KErrNone)
{
iReceiving = ETrue;
}
else
{
iObserver.BtReadComplete(err);
}
}
EXPORT_C void CBluetoothIncomingSerialConnection::CancelRead()
{
TRACE1("CBluetoothIncomingSerialConnection::CancelRead");
iSocket->CancelRead();
iReceiving = EFalse;
}
EXPORT_C void CBluetoothIncomingSerialConnection::ShutDown()
{
iSocket->Shutdown(RSocket::EImmediate);
}
void CBluetoothIncomingSerialConnection::HandleConnectCompleteL(TInt _BTDEB(aErr))
{
TRACE2("CBluetoothIncomingSerialConnection::HandleConnectCompleteL(%d)", aErr);
}
void CBluetoothIncomingSerialConnection::HandleAcceptCompleteL(TInt _BTDEB(aErr))
{
TRACE2("CBluetoothIncomingSerialConnection::HandleAcceptCompleteL(%d)", aErr);
}
void CBluetoothIncomingSerialConnection::HandleShutdownCompleteL(TInt aErr)
{
TRACE2("CBluetoothIncomingSerialConnection::HandleShutdownCompleteL(%d)", aErr);
iObserver.BtShutdownComplete(aErr);
}
void CBluetoothIncomingSerialConnection::HandleSendCompleteL(TInt aErr)
{
TRACE1("CBluetoothIncomingSerialConnection::HandleSendCompleteL");
__ASSERT_ALWAYS(iSending, PANIC());
iSending = EFalse;
iObserver.BtWriteComplete(aErr);
}
void CBluetoothIncomingSerialConnection::HandleReceiveCompleteL(TInt aErr)
{
TRACE1("CBluetoothIncomingSerialConnection::HandleReceiveCompleteL");
__ASSERT_ALWAYS(iReceiving, PANIC());
iReceiving = EFalse;
iObserver.BtReadComplete(aErr);
}
void CBluetoothIncomingSerialConnection::HandleIoctlCompleteL(TInt _BTDEB(aErr))
{
TRACE2("CBluetoothIncomingSerialConnection::HandleIoctlCompleteL(%d)", aErr);
}
void CBluetoothIncomingSerialConnection::HandleActivateBasebandEventNotifierCompleteL(TInt _BTDEB(aErr), TBTBasebandEventNotification& /*aEventNotification*/)
{
TRACE2("CBluetoothIncomingSerialConnection::HandleActivateBasebandEventNotifierCompleteL(%d)", aErr);
}
void CBluetoothIncomingSerialConnection::HandleNewConnection(CBluetoothSocket* aConnectedSocket)
{
TRACE1("CBluetoothIncomingSerialConnection::HandleNewConnection");
__ASSERT_ALWAYS(iSocket == aConnectedSocket, PANIC());
iSocketReady = ETrue;
iObserver.BtSerialConnected();
}
void CBluetoothIncomingSerialConnection::HandleConnectFailed(TInt aError)
{
TRACE2("CBluetoothIncomingSerialConnection::HandleConnectFailed", aError);
iSocketReady = EFalse;
iObserver.BtSerialError(aError);
}
CBtRegQuery::CBtRegQuery(CBluetoothIncomingSerialConnection& aOwner)
: CActive(CActive::EPriorityStandard), iOwner(aOwner)
{
CActiveScheduler::Add(this);
}
void CBtRegQuery::Start(CBTRegistryResponse& aBtResponse)
{
iResponse = &aBtResponse;
iResponse->Start(iStatus);
SetActive();
}
void CBtRegQuery::RunL()
{
iOwner.QueryComplete(iStatus.Int());
}
void CBtRegQuery::DoCancel()
{
iResponse->Cancel();
// nasty race condition inside CBTRegistryResponse which means the cancal call may not
// request out TRequestStatus (if DoCancel doesn't need to be called)
if (iStatus == KRequestPending)
{
TRequestStatus* stat = &iStatus;
User::RequestComplete(stat, KErrCancel);
}
}