/*
* Copyright (c) 2006 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:
*
*/
/** Add TRAP harnesses for leaving functions such as iServiceSearcher->ConnectL
Decide what to do with Copyrighted Nokia code */
#include "ObjectExchangeClient.h"
#include "ObjectExchangeServiceSearcher.h"
#include "BTObjectExchange.pan"
#include <e32svr.h>
// Define DEBUG trace for debug builds
#ifdef _DEBUG
#define TRACE(a) RDebug::Print a
#else
#define TRACE(a)
#endif
CObjectExchangeClient* CObjectExchangeClient::NewL()
{
CObjectExchangeClient* self = NewLC();
CleanupStack::Pop(self);
return self;
}
CObjectExchangeClient* CObjectExchangeClient::NewLC()
{
CObjectExchangeClient* self = new (ELeave) CObjectExchangeClient();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CObjectExchangeClient::CObjectExchangeClient()
: CActive(CActive::EPriorityStandard),
iState(EWaitingToGetDevice) // Go to initial state and wait for ConnectL function call
{
CActiveScheduler::Add(this);
}
void CObjectExchangeClient::ConstructL()
{
iServiceSearcher = CObjectExchangeServiceSearcher::NewL();
}
CObjectExchangeClient::~CObjectExchangeClient()
{
Cancel(); // Cancel any outstanding request on this object
delete iCurrObject;
iCurrObject = NULL;
delete iServiceSearcher; // iServiceSearcher's destructor completes any outstanding request
iServiceSearcher = NULL;
delete iClient;
iClient = NULL;
}
void CObjectExchangeClient::DoCancel()
{
// Add Cancelling for outstanding request caused by
// iServiceSearcher->SelectDeviceByDiscoveryL(iStatus)
// and iServiceSearcher->FindServiceL(iStatus);
// NOTE: works now if the iServiceSearcher is deleted, but not if cancelled
// SOLUTION: delete and recreate iServiceSearcher in DoCancel? Or implement
// Cancel to iServiceSearcer!
if (iState != EWaitingToGetDevice && iClient)
{
iClient->Abort();
delete iClient; // must be deleted so that connection is not left open
// if sender cancels before receiver accepts connection
iClient = NULL;
}
iServiceSearcher->Cancel();
iStatus = KErrNone; // At least emulated version does not work without this
iState = EWaitingToGetDevice;
User::RequestComplete( iObserverStatus, KErrCancel );
}
void CObjectExchangeClient::RunL()
{
if (iStatus != KErrNone)
{
switch (iState)
{
case EGettingDevice:
case EGettingService:
case EGettingConnection:
case EDisconnecting:
case EWaitingToSend:
User::RequestComplete(iObserverStatus, iStatus.Int()); // Relay error codes
iState = EWaitingToGetDevice; // Return always to initial state
break;
default:
Panic(EBTObjectExchangeUnexpectedLogicState);
break;
}
}
else
{
switch (iState)
{
case EGettingDevice:
iState = EGettingService;
iStatus = KRequestPending; // NOTE: Setting this should be the responsibility
// of the called function
// move to CBTServiceSearcher::FindServiceL?
iServiceSearcher->FindServiceL(iStatus); // Find the OBEX service on the target device
SetActive();
break;
case EGettingService:
iState = EGettingConnection;
ConnectToServerL(); // Connect to the OBEX service port on the target device
break;
case EGettingConnection:
iState = EWaitingToSend;
User::RequestComplete(iObserverStatus, KErrNone); // ConnectL was succesfull
break;
case EWaitingToSend:
User::RequestComplete(iObserverStatus, KErrNone); // SendObjectL was successfull
break;
case EDisconnecting:
iState = EWaitingToGetDevice;
User::RequestComplete(iObserverStatus, KErrNone); // DisconnectL succeeded
break;
default:
Panic(EBTObjectExchangeSdpRecordDelete);
break;
};
}
}
void CObjectExchangeClient::ConnectL(TRequestStatus& aObsRequestStatus)
{
aObsRequestStatus = KRequestPending; // Have the observer wait for this request to complete
iObserverStatus = &aObsRequestStatus; // Store the observer's TRequestStatus for later use
if (iState == EWaitingToGetDevice && !IsActive())
{
iState = EGettingDevice;
iServiceSearcher->SelectDeviceByDiscoveryL(iStatus); // Show a device selection dialog
SetActive();
}
else
{
// Inform the observer that connection cannot be initiated
User::RequestComplete(iObserverStatus, KErrInUse );
return;
}
}
void CObjectExchangeClient::ConnectToServerL()
{
TObexBluetoothProtocolInfo protocolInfo;
protocolInfo.iTransport.Copy(KServerTransportName);
protocolInfo.iAddr.SetBTAddr(iServiceSearcher->BTDevAddr());
protocolInfo.iAddr.SetPort(iServiceSearcher->Port());
if (iClient)
{
delete iClient;
iClient = NULL;
}
iClient = CObexClient::NewL(protocolInfo);
iClient->Connect(iStatus);
SetActive();
}
void CObjectExchangeClient::SendObjectL( const TDesC& aFileName, TRequestStatus& aObsRequestStatus)
{
aObsRequestStatus = KRequestPending; // Have the observer wait for this request to complete
iObserverStatus = &aObsRequestStatus; // Store the observer's TRequestStatus for later use
if (iState != EWaitingToSend)
{
// Inform the user that sending is not possible because there is no connection
User::RequestComplete(iObserverStatus, KErrDisconnected);
return;
}
else if (IsActive())
{
// Inform the user that there is already an outstanding request on this object
User::RequestComplete(iObserverStatus, KErrInUse);
return;
}
delete iCurrObject;
iCurrObject = NULL;
TRACE((aFileName));
iParse.Set( aFileName, NULL, NULL );
// Create the OBEX object from the file
TRAPD(err, iCurrObject = CObexFileObject::NewL(aFileName));
if (err)
{
TRACE((_L("_DEBUG: Error creating CObexFileObject")));
// Inform the observer that file was not found
User::RequestComplete(iObserverStatus, err);
return;
}
else
{
/* Set proper values for the object info ? */
// Fill in the object info
iCurrObject->SetDescriptionL(_L("OBEX file object"));
iCurrObject->SetNameL( iParse.NameAndExt());
iCurrObject->SetTypeL(_L8("text/plain")); // NOTE: Sending everything as text/plain
// Update the header mask
TObexHeaderMask headermask = iCurrObject->HeaderMask(); // get current header mask
headermask = headermask | KObexHdrName | KObexHdrType | KObexHdrDescription;
iCurrObject->SetHeaderMask(headermask);
}
// Send the object
iClient->Put(*iCurrObject, iStatus);
SetActive();
}
void CObjectExchangeClient::StopL()
{
if (iClient && iClient->IsConnected())
{
iClient->Abort();
iState = EWaitingToGetDevice;
}
}
void CObjectExchangeClient::DisconnectL(TRequestStatus& aObsRequestStatus)
{
aObsRequestStatus = KRequestPending; // Have the observer wait for this request to complete
iObserverStatus = &aObsRequestStatus; // Store the observer's TRequestStatus for later use
if (iState == EWaitingToGetDevice)
{
// Not connected, inform the observer
User::RequestComplete(iObserverStatus, KErrNone);
return;
}
if (iState == EWaitingToSend)
{
iState = EDisconnecting;
iClient->Disconnect(iStatus);
SetActive();
}
else
{
// Busy connecting or disconnecting
User::RequestComplete(iObserverStatus, KErrInUse);
return;
}
}
TBool CObjectExchangeClient::IsBusy()
{
return IsActive();
}
TBool CObjectExchangeClient::IsConnected()
{
return iState == EWaitingToSend;
}