diff -r 000000000000 -r c9bc50fca66e usbmgmt/usbmgrtest/ObexClassController/test/src/simpleObexClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbmgmt/usbmgrtest/ObexClassController/test/src/simpleObexClient.cpp Tue Feb 02 02:02:59 2010 +0200 @@ -0,0 +1,585 @@ +/* +* 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 + +#include +#include +#include "simpleObexClient.h" +#include "simpleObexApp.h" +#include "obexAppConstants.h" + + + +/** + * Constructor, ownership of Console is passed. + */ +CObexClientHandler::CObexClientHandler(CActiveConsole* aParent) + : CActive(CActive::EPriorityStandard), + iParent(aParent) + { + iClient = NULL; + iObject = NULL; + iState = EIdle; + } + + +/** + * NewL function. + */ +CObexClientHandler* CObexClientHandler::NewL(CActiveConsole* aParent, TTransport aTransport) + { + CObexClientHandler* self = new (ELeave) CObexClientHandler(aParent); + + CleanupStack::PushL (self); + self->ConstructL(aTransport); + CActiveScheduler::Add (self); + CleanupStack::Pop (); + return (self); + } + + +/** + * 2nd phase constructor. Responsible for determining which + * transport has been selected and to create a new OBEX Client. + */ +void CObexClientHandler::ConstructL(TTransport aTransport) + { + + // Construct client if bluetooth selected + if (aTransport == EBluetooth) + { + iDevAddr = devAddr; // take the Bluetooth address + + //start the SDP Query + delete iSdpServiceFinder; + iSdpServiceFinder=0; + iSdpServiceFinder = CRFCOMMServiceFinder::NewL(ftpUuid, iDevAddr, *this); + // Start search process + iSdpServiceFinder->FindPortL(); + iParent->Console()->Printf(_L("\nSearching for SDP service....\n")); + } + else if (aTransport == EIrda) + { + // Create transport info + TObexIrProtocolInfo transportInfo; + //assigning the unique name for the irda transport + transportInfo.iTransport = KObexIrTTPProtocol; + //assigning irda specific attributes + transportInfo.iClassName = KIrdaClassName; + transportInfo.iAttributeName = KIrdaTransportAttrName; + + iClient = CObexClient::NewL (transportInfo); //create the obex client + iParent->iMode = E_Client; + } + else if (aTransport == EUsb) + { + // Create transport info + TObexUsbProtocolInfo aInfo; + aInfo.iTransport = KObexUsbProtocol; + aInfo.iInterfaceStringDescriptor = KClientInterfaceDescriptor; + + iClient = CObexClient::NewL (aInfo);// Create the CObexClient + } + else if (aTransport == EWin32Usb) + { + // Ensure win32usb Obex transport plugin exists + // Create transport info + TObexUsbProtocolInfo aInfo; + aInfo.iTransport = KObexWin32UsbProtocol; + aInfo.iInterfaceStringDescriptor = KClientInterfaceDescriptor; + + iClient = CObexClient::NewL (aInfo); + } + else + { + User::Invariant(); + } + + // Setup Obex objects + iFileObject = CObexFileObject::NewL(); + iObjectBuffer = CBufFlat::NewL(KBufExpandSize); + iObject = CObexBufObject::NewL(iObjectBuffer); + iObexName = KNullDesC; + iGetType = KObjectType; + + // Create file session and create a new private path on drive C + RFs fileSession; + fileSession.Connect(); + + fileSession.CreatePrivatePath(EDriveC); + fileSession.SetSessionToPrivate(EDriveC); + fileSession.SessionPath(iSessionPath); + + // Copy the files from oby file ro the newly created path + BaflUtils::CopyFile(fileSession, KFilePath1, KFilename1,0); + BaflUtils::CopyFile(fileSession, KFilePath2, KFilename2,0); + BaflUtils::CopyFile(fileSession, KFilePath3, KFilename3,0); + + fileSession.Close(); + + // Assign file names + iFilename1 = KFilename1; + iFilename2 = KFilename2; + iFilename3 = KFilename3; + + + } + + +/** + * Destructor. + */ +CObexClientHandler::~CObexClientHandler() + { + // do cleanup + Cancel(); + delete iObject; + delete iFileObject; + delete iClient; + delete iObjectBuffer; + delete iTargetHeaderObject; + delete iSdpServiceFinder; + } + +/** + * This function is called when the SDP search finishes. + * If search was successful then the OBEX port number is + * taken an used in starting the OBEX client. + * If unsuccessful, go back to the initial menu. + */ +void CObexClientHandler::SearchResult(TInt aError, TUint8 aPort) + { + // Service not supported? + if (aError != KErrNone) + { + iParent->Console()->Printf(_L("\r\n Could not find SDP service in remote device : error %d \r\n"),aError); + iParent->iMode = E_Inactive; + iParent->Cancel(); + } + + + // Set protocol info for bluetooth + + TObexBluetoothProtocolInfo aInfo; + aInfo.iAddr.SetBTAddr(iDevAddr); + aInfo.iAddr.SetPort(aPort); + aInfo.iTransport = KObexRfcommProtocol; + //now create the obex client... + TRAPD(error,iClient = CObexClient::NewL (aInfo)); + if (error) + { + iParent->Console()->Printf(_L("\r\n Could not create client! : error %d \r\n"),error); + iParent->iMode = E_Inactive; + iParent->Cancel(); + } + + iParent->Console()->Printf(_L("\nSDP search complete OK!\n")); + iParent->iMode = E_Client; + + iParent->RequestCharacter(); + + } + + + +/** + * This function performs the actual connection of client to server. + */ + +void CObexClientHandler::Connect() + { + if(IsActive()) + { + iParent->Console()->Printf(KAlreadyActive); + return; + } + + TObexConnectInfo iLocalInfo = iClient->LocalInfo(); + iLocalInfo.iWho = KNullDesC8; + iLocalInfo.iWho = EPOCIDENT; + iLocalInfo.iWho.Append(KLocalInfoAppend); + // Connect to Obex client + iClient->Connect(iStatus); + SetActive(); + iState = EConnecting; + } + + +/** + * This fucntion performs the disconnection from OBEX client and server + */ +void CObexClientHandler::Disconnect() + { + if(IsActive()) + { + iParent->Console()->Printf(KAlreadyActive); + return; + } + // Disconnect from Obex client + iClient->Disconnect(iStatus); + SetActive(); + iState = EDisconnecting; + } + + +/** + * This function is called when an OBEX get is requested by name. + * It takes the current name of the OBEX object, replaces it with + * a user defined name. it then performs a Get on this object name. + */ +void CObexClientHandler::GetByNameL() + { + if(IsActive()) + { + iParent->Console()->Printf(KAlreadyActive); + return; + } + + iObject->Reset (); + // Call SetName passing current name + // This will set a newly selected name from the user + SetName(iObexName); + // Set the name + iObject->SetNameL (iObexName); + // Call get with required object + iClient->Get(*iObject, iStatus); + SetActive(); + iState = EGetting; + } + + + +/** + * This function is a wrapper for the CObexClient::Put function. + * It is responsible for setting up a new Obex object from a specified file. + * It then performs the Put operation. + */ +void CObexClientHandler::Put(TDes& aFilename) + { + if(IsActive()) + { + iParent->Console()->Printf(KAlreadyActive); + return; + } + + // Setup the object from file + TInt err = SetUpObjectFromFile (aFilename); + // Advise user if unsuccessful + if( err != KErrNone) + { + iParent->Console()->Printf(_L("\r\n Couldnt set up object : error %d \r\n"),err); + Disconnect(); + return; + } + // Call the put + iClient->Put(*iFileObject,iStatus); + SetActive(); + iState = EPutting; + } + + +/** + * This function is responsible for initiating a + * client/server connection with authentication. + * The password is set in source. + */ +void CObexClientHandler::ConnectWithAuthenticationL() + { + if(IsActive()) + { + iParent->Console()->Printf(KAlreadyActive); + return; + } + // Set generic password + iChallengePassword = KAuthPassword; + // Connect client to server sending password + iClient->ConnectL(iChallengePassword, iStatus); + // Active the active object + SetActive(); + iState = EConnecting; + } + +/** + * This function is called from within the GetByName function. + * It takes in the current object name and changes it to a user + * defined alternative. + */ +void CObexClientHandler::SetName(TDes& aName) + { + TBuf<64> oldName; + oldName = aName; + + TKeyCode aCode; + TBuf<1> aChar; + iParent->Console()->Printf(_L("\nEnter a name: %S"),&aName); + FOREVER + { + aCode = iParent->Console()->Getch(); + aChar.SetLength(0); + aChar.Append(aCode); + + iParent->Console()->Printf(_L("%S"),&aChar); + + // If finish editing string + if (aCode == EStdKeyDelete) + break; + + // if remove last character + if ((aCode == EStdKeyHome)&&(aName.Length() != 0)) + aName.SetLength((aName.Length()-1)); + else + aName.Append(aCode); + } + iParent->Console()->Printf(_L("\n")); + + + } + + + +/** + * This is the active object RunL function. + * When the function is called the currently selected mode of operation + * is examined and then dealt with accordingly. + * It displays the active object iStatus current state to the user. + */ +void CObexClientHandler::RunL () + { + if (iStatus != KErrNone) + {// Handle error + } + + TBuf<80> filename; + switch (iState) + { + // If we were connecting, and iStatus has completed then we want to change iState to EConnected + case EConnecting: + iParent->Console()->Printf(_L("\r\nConnect completed with error code: %d\r\n\r\n"),iStatus.Int()); + iState = EConnected; + break; + // If we were performing a put and the iStatus has completed change iState to EConnected + case EPutting: + iState = EConnected; + iParent->Console()->Printf(_L("\r\nPut completed with error code: %d\r\n\r\n"),iStatus.Int()); + break; + // If we were performing a get and the iStatus has completed change iState to EConnected + // Also we want to write the received object to file + case EGetting: + iState = EConnected; + iParent->Console()->Printf(_L("\r\nGet completed with error code: %d\r\n\r\n"),iStatus.Int()); + DisplayObjectInformation(); + filename = iSessionPath; + filename.Append(iObject->Name()); + // Write objects data to file, test if the file already exists as well + if (iObject->WriteToFile(filename) == KErrAlreadyExists) + { + iParent->Console()->Printf(_L("\r\nWrite failed, File Already Exists\n")); + } + iObject->Reset (); + break; + // If we wanted to disconnect and iStatus has completed, then go back to original state + case EDisconnecting: + iParent->Console()->Printf(_L("\r\nDisconnect completed with error code: %d\r\n\r\n"),iStatus.Int()); + iState = EIdle; + + default: + iParent->Console()->Printf(_L("\r\nTest Code is in an incorrect state: %d\r\n\r\n"),iState); + break; + } + + } + +/** + * This is the active object DoCancel function. + */ +void CObexClientHandler::DoCancel() + { + delete iClient; + iClient = NULL; + } + + +/** + * DisplayObjectInformation prints information of the received object. + */ +void CObexClientHandler::DisplayObjectInformation() + { + // Display Contents of CBufFlat data on current console + iParent->Console()->Printf(_L("Size of received object = %d\n"),iObjectBuffer->Size()); + TDateTime dt = iObject->Time().DateTime(); + iParent->Console()->Printf(_L("\r\nTimestamp: %d/%d/%d, %d:%d:%d\r\n\r\n"), + dt.Day(), dt.Month()+1, dt.Year(), dt.Hour(), dt.Minute(), dt.Second()); + + TBuf8<1024> tempBuffer; + iObjectBuffer->Read(0, tempBuffer, tempBuffer.MaxSize() < iObjectBuffer->Size() ? tempBuffer.MaxSize() : iObjectBuffer->Size()); + // Printf fails with Descriptor bigger than X hundred bytes so write byte at a time + for(TInt count = 0; count < tempBuffer.Size(); count++) + { + iParent->Console()->Printf(_L("%C"),tempBuffer[count]); + } + } + + + +/** + * This function is called when a Put operation has started. + * It takes a filename and then attempts to setup an OBEX object + * from that file. Returns the appropriate error code, if the + * file didn't exist then this function creates a new file of + * the same name. + */ +TInt CObexClientHandler::SetUpObjectFromFile(TDes& aFilename) + { + // Try to create CObexFileObject with filename + TRAPD (err, iFileObject->InitFromFileL (aFilename)); + if (err != KErrNone) + { + RFs fs; + RFile f; + err = fs.Connect(); + if (err== KErrNone) + { + err = fs.CreatePrivatePath(EDriveC); + } + + if (err== KErrNone || err == KErrAlreadyExists ) + { + err = fs.SetSessionToPrivate(EDriveC); + } + + if (err == KErrNone) + { + // File didn't exist so create a file of same name in it place + err = f.Create (fs, aFilename, EFileShareExclusive | EFileWrite); + } + + if (err != KErrNone) + { + iParent->Console()->Printf(_L("\r\nError reading '%s'.\r\nI tried to create this file for you, but failed to do that too. Sorry.\r\n\r\n"), aFilename.PtrZ ()); + } + else + { + f.Write (_L8("Test file for sending from EPOC\r\n\r\nLooks like obex is sending OK!!\r\n")); + f.Close (); + iParent->Console()->Printf(_L("\r\nFile '%s' did not exist, so I've created one.\r\nPlease try again.\r\n\r\n"), aFilename.PtrZ ()); + } + fs.Close (); + + } + + return (err); + + } + + + +/** + * NewL function for CRFCOMMServiceFinder + */ + +CRFCOMMServiceFinder* CRFCOMMServiceFinder::NewL( const TUUID& aServiceClass, + const TBTDevAddr& aDevAddr, + MRFCOMMServiceSeeker& aSeeker) + { + CRFCOMMServiceFinder* self= new (ELeave) CRFCOMMServiceFinder(aSeeker); + CleanupStack::PushL(self); + self->ConstructL(aDevAddr, aServiceClass); + CleanupStack::Pop(); + return (self); + } + +/** + * Destructor. + */ +CRFCOMMServiceFinder::~CRFCOMMServiceFinder() + { + delete iPattern; + delete iAgent; + } + +/** + * Constructor. + */ +CRFCOMMServiceFinder::CRFCOMMServiceFinder(MRFCOMMServiceSeeker& aSeeker) +: iSeeker(aSeeker) + { + } + +/** + * 2nd phase constructor. Sets the seach pattern for SDP with the UUID supplied. + * Then Creates a new SDP agent with the device address supplied. + */ +void CRFCOMMServiceFinder::ConstructL(const TBTDevAddr& aDevAddr, const TUUID& aServiceClass) + { + iPattern=CSdpSearchPattern::NewL(); + iPattern->AddL(aServiceClass); + iAgent=CSdpAgent::NewL(*this, aDevAddr); + // Filter out classes that arent FTP + iAgent->SetRecordFilterL(*iPattern); + } + +/** + * This function is responsible for calling the SDP agent NextRecordRequestL + * function, this gets the next service record that the device has registered + * in the SDP database. + */ +void CRFCOMMServiceFinder::FindPortL() + { + iPort=KNotAPort; //0xFF will never be returned from a query, + //because RFCOMM server channels only + //go up to 30. + + iAgent->NextRecordRequestL(); + } + + +/** + * This function is from the MSdpAgentNotify interface and is called when there + * are no more SDP records registered in the database. It calls SearchResult implemented + * by this class. + */ +void CRFCOMMServiceFinder::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt /*aTotalRecordsCount*/) + { + if(aError) + iSeeker.SearchResult(aError,KNoPort); + else + { + //We have the record, kick off the attribute request + TRAPD(err,iAgent->AttributeRequestL(aHandle,KSdpAttrIdProtocolDescriptorList )); + if(err) + iSeeker.SearchResult(err,KNoPort); + } + } + + + +/** + * This function comes from the MSdpAgentNotifer interface, It is called when + * the attribute request process has finished. + */ +void CRFCOMMServiceFinder::AttributeRequestComplete(TSdpServRecordHandle /*aHandle*/, TInt aError) + { + if(aError!=KErrNone || iPort==KNotAPort) + iSeeker.SearchResult(aError?aError:KErrNotFound,KNoPort); + else + iSeeker.SearchResult(KErrNone, iPort); + } + + + +