/*
* Copyright (c) 2005-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:
*
*/
#include <e32base.h>
#include <obexconstants.h>
#include "simpleObexServer.h"
#include "simpleObexApp.h"
#include "obexAppConstants.h"
/**
* Constructor.
*/
CObexServerHandler::CObexServerHandler(CActiveConsole* aParent)
:iAcceptPuts(ETrue)
{
iParent = aParent;
iServer = NULL;
iObject = NULL;
}
/**
* NewL function
*/
CObexServerHandler* CObexServerHandler::NewL(CActiveConsole* aParent, TTransport aTransport)
{
CObexServerHandler* self = new (ELeave) CObexServerHandler(aParent);
CleanupStack::PushL(self);
self->ConstructL(aTransport);
CleanupStack::Pop();
return (self);
}
/**
* 2nd phase constructor. This function performs the initial steps needed in
* creating a new CObexServer object. It then creates the CObexServer object for the specified
* transport.
*
*/
void CObexServerHandler::ConstructL(TTransport aTransport)
{
iTransportLayer = aTransport;
if (aTransport == EBluetooth)
{
// Start bluetooth socket and set security
RSocketServ socketServ;
socketServ.Connect();
RSocket listen;
TInt test = listen.Open(socketServ, KRFCOMMDesC);
if (test == KErrNone)
{
iParent->Console()->Printf(_L("Socket Open ... Success\n"));
}
TBTSockAddr addr;
// Auto bind to RFComm port
addr.SetPort(KRfcommPassiveAutoBind);
TBTServiceSecurity serviceSecurity;
serviceSecurity.SetUid(KUidServiceSDP);
serviceSecurity.SetAuthentication(EFalse);
serviceSecurity.SetEncryption(EFalse);
serviceSecurity.SetAuthorisation(EFalse);
serviceSecurity.SetDenied(EFalse);
addr.SetSecurity(serviceSecurity);
TInt error;
// Set bluetooth protocol info
TObexBluetoothProtocolInfo info;
info.iAddr.SetPort(KObexTestPort);
info.iTransport = KRFCOMMDesC;
TRAP(error,iServer = CObexServer::NewL(info));
if (error)
{
iParent->Console()->Printf(_L("\r\n Could not create obex server! : error %d \r\n"),error);
iParent->iMode = E_Inactive;
iParent->iMode = E_Server;
iParent->Cancel(); // cancel request for key
}
// Add services to the Service discovery database
User::LeaveIfError(iSdp.Connect());
User::LeaveIfError(iSdpdb.Open(iSdp));
TSdpServRecordHandle ftphandle;
iSdpdb.CreateServiceRecordL(ftpUuid, ftphandle);
iSdpdb.UpdateAttributeL(ftphandle, KSdpAttrIdServiceName, KServerDesC);
iProtDescList = CSdpAttrValueDES::NewDESL(0);
iProtDescList
->StartListL()
->BuildDESL()
->StartListL()
->BuildUUIDL(KL2CAPUUID)
->EndListL()
->BuildDESL()
->StartListL()
->BuildUUIDL(KRfcommUuid)
->BuildUintL(TSdpIntBuf<TInt8>(KObexTestPort))
->EndListL()
->BuildDESL()
->StartListL()
->BuildUUIDL(KObexProtocolUuid)
->EndListL()
->EndListL();
// Update attribute
iSdpdb.UpdateAttributeL(ftphandle, KProtocolDescriptorListUUID, *iProtDescList); // put into both records
delete iProtDescList;
User::LeaveIfError(listen.Bind(addr));
TInt queueSize=2;
User::LeaveIfError(listen.Listen(queueSize));
iParent->Console()->Printf(_L("\n.....Now Listening.....\n"));
}
else if (aTransport == EIrda)
{
//creating the transport info
TObexIrProtocolInfo transportInfo;
transportInfo.iAddr.SetPort(KAutoBindLSAP);//default obex server for now
transportInfo.iTransport = KObexIrTTPProtocol;
transportInfo.iClassName = KIrdaClassName;
transportInfo.iAttributeName = KIrdaTransportAttrName;
iServer = CObexServer::NewL (transportInfo);
}
else if (aTransport == EWin32Usb)
{
// Create transport info
TObexUsbProtocolInfo aInfo;
aInfo.iTransport = KObexWin32UsbProtocol;
aInfo.iInterfaceStringDescriptor = KServerInterfaceDescriptor;
iServer = CObexServer::NewL (aInfo);
}
// Now that the transport has been selected and Obex Server started
// We need to do some initialisation with Obex Objects so that we are
// prepared to deal with Put/Get requests from the client
iObject = CObexBufObject::NewL (NULL);
iBuf = CBufFlat::NewL(KServerBufExpandSize);
iBuf->ResizeL(KServerBufExpandSize);// Resize the buffer
iObject = CObexBufObject::NewL(NULL);
iObject->SetDataBufL(iBuf);
//Create the RFile to be used
User::LeaveIfError(iFs.Connect());
User::LeaveIfError(iFs.CreatePrivatePath(EDriveC));
User::LeaveIfError(iFs.SetSessionToPrivate(EDriveC));
User::LeaveIfError(iFs.SessionPath( iSessionPath ));
// Start the server
User::LeaveIfError(iServer->Start (this));
}
/**
* This function stops the OBEX server
*/
void CObexServerHandler::Stop()
{
if (iServer)
{
iServer->Stop();
}
}
/**
* Destructor.
*/
CObexServerHandler::~CObexServerHandler ()
{
Stop();
iSdpdb.Close();
iSdp.Close();
delete iObject;
delete iBuf;
delete iServer;
}
/**
* This function enables authentication on the OBEX server.
* The password is defined in source.
*/
void CObexServerHandler::EnableAuthenticationL()
{
iChallengePassword = KAuthPassword;
iServer->SetChallengeL(iChallengePassword);
iIsAuthenticationEnabled = ETrue;
}
/**
* This function disables authentication on the server.
*/
void CObexServerHandler::DisableAuthentication()
{
iServer->ResetChallenge();
iIsAuthenticationEnabled = EFalse;
}
// MObexServerNotify interface functions
/**
* Called if an OBEX protocol error occurs.
*/
void CObexServerHandler::ErrorIndication (TInt aError)
{
iParent->Console()->Printf(_L("Obex Server error %d"), aError);
}
/**
* Called when the underlying transport connection is made from a remote client to the server.
*/
void CObexServerHandler::TransportUpIndication ()
{
iParent->Console()->Printf(_L("\nTransport started\n"));
}
/**
* Called when the transport connection is dropped (by either party).
*/
void CObexServerHandler::TransportDownIndication ()
{
iParent->Console()->Printf(_L("\nTransport down\n"));
}
/**
* Called when an OBEX connection is made from a remote client.
*/
TInt CObexServerHandler::ObexConnectIndication(const TObexConnectInfo& aRemoteInfo, const TDesC8& /*aInfo*/)
{
iParent->Console()->Printf(_L("\r\nCObexServerHandler::ObexConnectIndication"));
iParent->Console()->Printf(_L("\r\nConnected to machine with OBEX version %d.%d\r\n"),
aRemoteInfo.VersionMajor (), aRemoteInfo.VersionMinor ());
return (KErrNone);
}
/**
* Called on a (graceful) OBEX disconnection by the client.
*/
void CObexServerHandler::ObexDisconnectIndication (const TDesC8& /*aInfo*/)
{
iParent->Console()->Printf(_L("\r\nObex Disconnected\r\n\r\n"));
}
/**
* Called on receipt of the first packet of a (valid) put request.
*/
CObexBufObject* CObexServerHandler::PutRequestIndication ()
{
iParent->Console()->Printf(_L("Receiving object...\r\n"));
iObject->Reset ();
if ( iAcceptPuts)
return (iObject);
else
return (NULL);
}
/**
* Called on receipt of every packet of an OBEX PUT operation.
*/
TInt CObexServerHandler::PutPacketIndication ()
{
TUint length = iObject->Length();
TUint received = iObject->BytesReceived();
TUint8 percent = 0;
if (length > 0)
{
percent = TUint8((100 * received) / length);
iParent->Console()->Printf(_L("\r%d %% "), percent);
}
else
{
iParent->Console()->Printf(_L("\r%d "), iObject->BytesReceived ());
}
return (KErrNone);
}
/**
* Called after the final put packet has been successfully received and parsed.
*/
TInt CObexServerHandler::PutCompleteIndication ()
{
TPtrC name=iObject->Name();
TBuf<100> type;
type.Copy(iObject->Type());
iParent->Console()->Printf(_L("\r\nSuccessfully received '%S'\r\nType[%d]: '%S'\r\n"), &name, type.Length(), &type);
TInt err = KErrNone;
TBuf<80> filename(iSessionPath);
filename.Append(iObject->Name());
err = iObject->WriteToFile(filename);
if (err == KErrAlreadyExists)
{
iParent->Console()->Printf(_L("\r\nWrite failed, File Already Exists\n"));
}
iObject->Reset ();
return (err);
}
/**
* Called when a full get request has been received from the client.
*/
CObexBufObject* CObexServerHandler::GetRequestIndication (CObexBaseObject* aRequiredObject)
{
TRAPD(err,SetUpGetObjectL(aRequiredObject));
if (err != KErrNone)
{
iParent->Console()->Printf(_L("\nSetUpGetObjectL() returned %d.\n"), err);
return NULL;
}
return (iObject);
}
/**
* Called for every packet of get reply sent by the server back to the client.
*/
TInt CObexServerHandler::GetPacketIndication ()
{
if (iObject->Length () > 0)
iParent->Console()->Printf(_L("\r%d %% "),
100 * iObject->BytesSent () / iObject->Length ());
else
iParent->Console()->Printf(_L("\r%d Bytes "), iObject->BytesSent ());
return (KErrNone);
}
/**
* Called when the final packet of the object has been returned to the client.
*/
TInt CObexServerHandler::GetCompleteIndication ()
{
iParent->Console()->Printf(_L("Obex Get Complete\r\n"));
iObject->Reset ();
return (KErrNone);
}
/**
* Called when an OBEX SETPATH command is received by the server.
*
*/
TInt CObexServerHandler::SetPathIndication (const CObex::TSetPathInfo& aPathInfo, const TDesC8& /*aInfo*/)
{
iParent->Console()->Printf(_L("Obex SetPath request:\r\n"));
iParent->Console()->Printf(_L(" --- Flags = '%d' - Constants = '%d' - "), aPathInfo.iFlags, aPathInfo.iConstants);
if (aPathInfo.iNamePresent)
iParent->Console()->Printf(_L("Name = %S\r\n"), &aPathInfo.iName);
else
iParent->Console()->Printf(_L("> No Name Present <\r\n"));
iParent->Console()->Printf(_L("\nReturning success...!\n"));
return (KErrNone);
}
/**
* Called when an abort packet is received from the client.
*/
void CObexServerHandler::AbortIndication ()
{
iParent->Console()->Printf(_L("Obex Operation aborted\r\n"));
if(iObject)
{
// Determine if we have recieved any amount of the object
// Return without notifing user if we haven't.
if(!iObject->BytesReceived())
return;
iParent->Console()->Printf(_L("\r\nWe have received part of an Obex object\r\n\r\n"));
iObject->Reset();
}
}
/**
* This is the function that sets up an object ready for a Get.
* It takes as a parameter the requested object and then examines it's
* name and if a filename matches then the object it setup from that file.
*/
void CObexServerHandler::SetUpGetObjectL(CObexBaseObject *aRequestedObject)
{
// Get the name of the requested object
TBuf<200> name (aRequestedObject->Name ());
if(name.Length())
{
iParent->Console()->Printf(_L("Obex Get Request for name '%s'\r\n"), name.PtrZ ());
}
else
{
iParent->Console()->Printf(_L("Obex Get Request unknown details\r\n"));
User::Leave(KErrNotSupported);
}
iObject->Reset();
RFs fs;
RFile f;
// Attempt to open the specified file
if ((fs.Connect () != KErrNone) ||
(f.Open (fs, name, EFileShareReadersOnly | EFileRead) != KErrNone))
{
iParent->Console()->Printf(_L("\r\nError reading '%S'."), &name);
User::Leave(KErrNotFound);
}
// We can now proceed in setting up the object using the file retrieved
TInt size = 0;
// Set size of file
User::LeaveIfError(f.Size (size));
// Resize buffer object
iBuf->ResizeL(size);
// Get a pointer to represent the data
TInt bufStart=0;
TPtr8 data (iBuf->Ptr(bufStart));
// Read data from file,
f.Read (data);
if (iBuf->Size() < size)
User::Leave(KErrGeneral);
// Set name of the object
iObject->SetNameL(name);
// Set length
iObject->SetLengthL(size);
TTime time;
if (f.Modified(time) == KErrNone)
iObject->SetTimeL(time);
}