messagingappbase/obexmtms/btmtm/btclient/source/btcmtm.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/obexmtms/btmtm/btclient/source/btcmtm.cpp	Fri Jun 04 10:25:39 2010 +0100
@@ -0,0 +1,314 @@
+// Copyright (c) 2004-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:
+// btcmtm.cpp
+//
+
+//class include
+#include <btcmtm.h>
+
+//system includes
+#include <e32std.h>
+#include <e32base.h>
+#include <txtrich.h>	// CRichText
+
+#include <mtmuids.h>	// KUidMtmQueryCanSendMsg
+#include <msvreg.h>		// CRegisteredMtmDll
+#include <mtmdef.h>		// KUidMtmQueryxxx & TMsvPartList flags
+#include <msvuids.h>	// KUidMsvMessageEntry
+#include "btmtmcmds.h"	//EBtMtmCmdSend
+
+//user includes
+#include <btheader.h>
+#include "btmsgtypeuid.h" //KUidMsgTypeBt
+#include <cobexsendoperation.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
+#include "msvconsts.h"
+#include <mtmuidsdef.hrh>
+#endif
+
+const TUint8 KObexConnectionIDHeader = 0xCB;
+
+CBtClientMtm::CBtClientMtm(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession)
+: CObexClientMtm(aRegisteredMtmDll, aMsvSession, KUidMsgTypeBt)
+/**
+ * Constructor--not for use by client applications
+ *
+ * @param aRegisteredMtmDll Registration data for MTM DLL.
+ * @param aMsvSession CMsvSession of the client requesting the object. 
+ */
+	{
+	}
+
+void CBtClientMtm::InitialiseHeaderL()
+/**
+ * Deletes the old header, then creates a new CBtHeader.
+ *
+ * @leave KErrXXX System-wide error codes if allocation fails
+ */
+	{
+	delete iHeader;
+	iHeader = 0;
+
+	iHeader = CBtHeader::NewL();
+	}
+
+EXPORT_C CBtClientMtm* CBtClientMtm::NewL(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession)
+/**
+ * Canonical NewL factory function. 
+ *
+ * @param aRegisteredMtmDll Reference to registration data for MTM DLL.
+ * @param aMsvSession Reference to CMsvSession of the client requesting the object.
+ * @return Pointer to a new, constructed CBtClientMtm
+ * @leave Leaves if no memory is available.
+ */
+	{
+	CBtClientMtm* self = new(ELeave) CBtClientMtm(aRegisteredMtmDll, aMsvSession);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CMsvOperation* CBtClientMtm::InvokeAsyncFunctionL(TInt aFunctionId, 
+												    const CMsvEntrySelection& aSelection,
+													TDes8& aParameter, 
+												    TRequestStatus& aCompletionStatus)
+/**
+ * Starts an asynchronous function as an active object. Only works for EBtcCmdSend.
+ *
+ * @param aFunctionId Identifier of the function to be invoked. Only supports EBtcCmdSend and
+ * KMTMStandardFunctionsSendMessage.
+ * @param aSelection Selection of message entries for the requested function to operate on.
+ * @param aParameter Buffer containing input and output parameters.
+ * @param aCompletionStatus Canonical TRequestStatus used for control of the active object.
+ * @return Pointer to a new asynchronously completing CMsvOperation. If failed, this is a completed operation with 
+ * status set to the relevant error code.
+ * @leave Leaves if no memory is available, or if the specified aFunctionId is unsupported.
+ */	{
+	__TEST_INVARIANT_VIRTUAL
+
+	CMsvOperation* op = NULL;
+	switch (aFunctionId)
+		{
+	case KMTMStandardFunctionsSendMessage:
+			{
+			// parameter ignored, it's assumed that the 1st addressee will contain all the
+			// required information to send this item. Only the 1st item in the selection
+			// list is sent.
+			CreateMessageOperationL(op, aSelection, aCompletionStatus);
+			break;
+			}
+	case EBtMtmCmdSend:
+			{
+			/*
+			In order to get our password over the client-server boundary without breaking the client interface
+			we will repack the client side package buffer into a server package buffer.
+			*/
+			TPckgBuf<CBtClientMtm::SBtcCmdSendServerParams> serverParams;
+
+			TPckgBuf<CBtClientMtm::SBtcCmdSendParams>& clientParams = (TPckgBuf<CBtClientMtm::SBtcCmdSendParams>&)aParameter;
+
+			/* at this point, it may be worth checking the length of the supplied password
+			and leaving with KErrArgument if it's longer than allowed */
+			if(!clientParams().iConnectPassword || clientParams().iConnectPassword->Length() > KBlueToothObexPasswordLength)
+				User::Leave(KErrArgument);
+				
+			serverParams().iTimeouts = clientParams().iTimeouts;
+			serverParams().iRemoteObexPort = clientParams().iRemoteObexPort;
+			serverParams().iConnectPassword = *(clientParams().iConnectPassword);
+
+			op = Session().TransferCommandL(aSelection,	aFunctionId, serverParams,
+											aCompletionStatus);
+			break;
+			}
+	default:
+		User::Leave(KErrNotSupported);
+		}
+	return(op); // ownership of op is passed to caller
+	}
+
+
+void CBtClientMtm::CreateMessageOperationL(
+	CMsvOperation*& aOperation, const CMsvEntrySelection& aSelection, TRequestStatus& aCompletionStatus)
+	{		
+	// must have at least 1 addressee (if more than 1 the others are ignored)
+	if (AddresseeList().Count() == 0)
+		{
+		User::Leave(KErrArgument);
+		}
+	
+	// extract and parse addressee information
+	TPckgBuf<CBtClientMtm::SBtcCmdSendServerParams> serverParams;
+	serverParams().iRemoteObexPort = 0;
+	
+	// Set some default values for the timeouts in case they have not been added to
+	// the addressee.
+	serverParams().iTimeouts.iConnectTimeout = 0;
+	serverParams().iTimeouts.iPutTimeout = 0;
+
+	// address already saved when addressee was added (and we know there is at least one)
+	TBuf8<KBlueToothObexDeviceAddressLength> addressIgnored; 
+	TBuf<KBlueToothObexPasswordLength> password;
+	ParseDestinationL(AddresseeList()[0], addressIgnored, password, 
+		serverParams().iTimeouts.iConnectTimeout, 
+		serverParams().iTimeouts.iPutTimeout);
+
+	serverParams().iConnectPassword = password;
+			
+	// obex send operation wrapper, supporting standard progress
+	CObexSendOperation* send = new(ELeave) CObexSendOperation(Session(), aCompletionStatus);
+	CleanupStack::PushL(send);
+	// start the send operation
+	CMsvOperation* op = 
+		Session().TransferCommandL(aSelection,	EBtMtmCmdSend, serverParams, send->iStatus);
+	CleanupStack::PushL(op);
+	send->Start(op);
+	CleanupStack::Pop(2, send); // op, send
+	aOperation = send;
+	}
+
+void CBtClientMtm::AddAddresseeL(const TDesC& anAddressee)
+	{
+	// check addressee parses ok - checks all fields (that are there)
+	TBuf8<KBlueToothObexDeviceAddressLength> address;
+	TBuf<KBlueToothObexPasswordLength> ignored1;
+	TInt ignored2(0);
+	TInt ignored3(0);
+	ParseDestinationL(anAddressee, address, ignored1, ignored2, ignored3);
+	
+	// parses ok, try to save it - fails if there is already an addressee
+	CObexClientMtm::AddAddresseeL(anAddressee);	
+
+	// parses and saves ok, store device address in header
+	iHeader->SetAddrL(address);
+	}
+
+/**
+ * Parse bluetooth addressee field
+ *
+ * @param aFieldTag Field tag ID (see TBtClientMtmAddresseeFieldType).
+ * @param aField The next field (descriptor buffer of the correct size for the given field).
+ * @param aFieldList Addressee field list.
+ * @leave Leaves with KErrArgument if parameter or formatting incorrect.
+ */
+TBool CBtClientMtm::ParseDestinationFieldL(TUint16 aFieldTag, TDes8& aField, TPtrC& aFieldList)
+	{
+	TBool isDeviceAddress = (aFieldTag == EDeviceAddress);
+
+	aField.Zero();
+	TInt length = aFieldList.Length();
+	if (!isDeviceAddress)
+		{
+		// end of field list
+		if (length == 0)
+			{
+			return EFalse;
+			}
+		// expecting tag
+		if (length < 2 || aFieldList[0] != ':' || aFieldList[1] != aFieldTag)
+			{
+			User::Leave(KErrArgument);
+			}
+		// remove tag and marker
+		aFieldList.Set(aFieldList.Right(aFieldList.Length() - 2));	
+		}
+
+	// locate next tag		
+	TInt fieldLength = aFieldList.Locate(':');
+	if (fieldLength == KErrNotFound)
+		{
+		fieldLength = aFieldList.Length();
+		}
+
+	// twice as many bytes
+	TInt fieldLength8 = fieldLength << 1;
+	if (fieldLength8 > aField.MaxLength())
+		{
+		User::Leave(KErrArgument);
+		}
+	
+	// copy field	
+	aField.Copy((TUint8*)aFieldList.Ptr(), fieldLength8);
+
+	// remove field from field list
+	aFieldList.Set(aFieldList.Right(aFieldList.Length() - fieldLength));	
+	
+	return ETrue;
+	}	
+	
+/**
+ * Parse bluetooth addressing information from addressee list.
+ *
+ * @param aDeviceAddress Device address (6 bytes).
+ * @param aPassword Password (max length 16).
+ * @param aConnectTimeout Connection timeout.
+ * @param aPutTimeout Put timeout.
+ * @leave Leaves with KErrArgument if parameter or formatting incorrect.
+ */
+void CBtClientMtm::ParseDestinationL(const TDesC& aFieldsToParse, TDes8& aDeviceAddress, 
+								   TDes16& aPassword, TInt& aConnectTimeout, TInt& aPutTimeout)
+	{
+	TPtrC16 fields(aFieldsToParse);
+
+	// get device address
+	if (ParseDestinationFieldL(EDeviceAddress, aDeviceAddress, fields))
+		{
+		// get password
+		TPtr8 password((TUint8*)aPassword.Ptr(), aPassword.MaxLength()<<1);
+		if (ParseDestinationFieldL(EPassword, password, fields))
+			{
+			aPassword.SetLength(password.Length()>>1);
+			// get connection timeout
+			TPckg<TInt> connectTimeout(aConnectTimeout);
+			TBool parsedOk = EFalse;
+
+			// The connect timeout can have a field tag defined by ETimeout, or a
+			// field tag defined by EAlternativeConnectTimeout. This is because an
+			// older version of code looked for the wrong tag (EAlternativeConnectTimeout),
+			// and we need to remain backward compatible with it.
+			TRAPD(err, parsedOk = ParseDestinationFieldL(ETimeout, connectTimeout, fields));
+
+			if (err == KErrArgument)
+				{
+				parsedOk = ParseDestinationFieldL(EAlternativeConnectTimeout, connectTimeout, fields);
+				}
+			else
+				{
+				User::LeaveIfError(err);
+				}
+
+			if (parsedOk)
+				{
+				// get put timeout
+				TPckg<TInt> putTimeout(aPutTimeout);
+				ParseDestinationFieldL(EPutTimeout, putTimeout, fields);
+				}
+			}
+		}
+	}
+
+
+
+#ifdef _DEBUG
+void CBtClientMtm::TestInvariant() const
+	{
+	__ASSERT_DEBUG(iMsvEntry &&
+				   iHeader &&
+				   (iMsvEntry->Entry().iMtm == KUidMsgTypeBt) &&
+				   (iMsvEntry->Entry().iType == KUidMsvMessageEntry),
+				   User::Invariant());
+	}
+#endif //_DEBUG
+