--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/bteng/btengdiscovery/src/btengsdpquery.cpp Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,360 @@
+/*
+* 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: Helper class for performing SDP queries.
+*
+*/
+
+
+
+#include <btsdp.h>
+
+#include "btengsdpquery.h"
+#include "btengdiscovery.h"
+#include "btengsdpattrparser.h"
+#include "debug.h"
+
+
+/** Array granularity for storing SDP attribute values (the number
+ * of attributes returned from an attribute search is expected
+ * to be small).
+ */
+const TInt KBTEngDefaultGranularity = 2;
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CBTEngSdpQuery::CBTEngSdpQuery( MBTEngSdpResultReceiver* aNotifier )
+: iAttrValArray( KBTEngDefaultGranularity ),
+ iResultNotifier( aNotifier )
+ {
+ }
+
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd-phase constructor
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::ConstructL()
+ {
+ TRACE_FUNC_ENTRY
+ iParser = CBTEngSdpAttrParser::NewL( &iAttrResArray );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CBTEngSdpQuery* CBTEngSdpQuery::NewL( MBTEngSdpResultReceiver* aNotifier )
+ {
+ CBTEngSdpQuery* self = new( ELeave ) CBTEngSdpQuery( aNotifier );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CBTEngSdpQuery::~CBTEngSdpQuery()
+ {
+ TRACE_FUNC_ENTRY
+ Cancel();
+ delete iSdpAgent;
+ delete iParser;
+ iResultNotifier = NULL;
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::Cancel()
+ {
+ TRACE_FUNC_ENTRY
+ if( iQueryType != EQueryIdle )
+ {
+ // Only call the agent when a search is active, as it
+ // involves some cleanup which is not necessary for every call.
+ iSdpAgent->Cancel();
+ iQueryType = EQueryIdle;
+ }
+ iRecHandleArray.Close();
+ iAttrResArray.Close();
+ iAttrValArray.ResetAndDestroy();
+ iRequestedAttrId = 0;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Service query
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::RemoteSdpQueryL( const TBTDevAddr& aAddr, const TUUID& aService )
+ {
+ TRACE_FUNC_ENTRY
+ CheckSdpAgentL( aAddr );
+ if( iQueryType == EQueryIdle )
+ {
+ iQueryType = EServiceQuery;
+ iAttrResArray.Close();
+ iAttrValArray.ResetAndDestroy();
+ iRequestedAttrId = 0;
+ }
+ iRecHandleArray.Close();
+ CSdpSearchPattern* searchPattern = CSdpSearchPattern::NewL();
+ CleanupStack::PushL( searchPattern );
+ searchPattern->AddL( aService );
+ iSdpAgent->SetRecordFilterL( *searchPattern ); // Copies searchpattern.
+ iSdpAgent->NextRecordRequestL();
+ CleanupStack::PopAndDestroy( searchPattern );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// Attribute query
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::RemoteSdpQueryL( const TBTDevAddr& aAddr,
+ const TSdpServRecordHandle aHandle, const TSdpAttributeID aAttrId )
+ {
+ TRACE_FUNC_ENTRY
+ CheckSdpAgentL( aAddr );
+ // this could be part of a ServiceSearchAttribute query.
+ if( iQueryType == EQueryIdle )
+ {
+ iQueryType = EAttrQuery;
+ iRecHandleArray.Close();
+ }
+ iRequestedAttrId = aAttrId;
+ iAttrResArray.Close();
+ iAttrValArray.ResetAndDestroy();
+ iSdpAgent->AttributeRequestL( aHandle, aAttrId );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// ServiceAttribute query
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::RemoteSdpQueryL( const TBTDevAddr& aAddr, const TUUID& aService,
+ const TSdpAttributeID aAttrId )
+ {
+ TRACE_FUNC_ENTRY
+ if( iQueryType != EQueryIdle )
+ {
+ User::Leave( KErrInUse );
+ }
+ iQueryType = EServiceAttrQuery;
+ iRequestedAttrId = aAttrId;
+ iRecHandleArray.Close();
+ iAttrResArray.Close();
+ iAttrValArray.ResetAndDestroy();
+ // First query for the requested service.
+ RemoteSdpQueryL( aAddr, aService );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MSdpAgentNotifier.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::NextRecordRequestComplete( TInt aError,
+ TSdpServRecordHandle aHandle, TInt aTotalRecordsCount )
+ {
+ TRACE_FUNC_ENTRY
+ if( aError == KErrNone && aTotalRecordsCount > 0 )
+ {
+ // Store the result and wait for the next.
+ iRecHandleArray.Append( aHandle );
+ TRAP( aError, iSdpAgent->NextRecordRequestL() );
+ }
+ else if( aError == KErrEof )
+ {
+ // The last notification does not contain any result anymore.
+ if( iQueryType == EServiceAttrQuery )
+ {
+ if( iRecHandleArray.Count() > 0 )
+ {
+ // Request the attribute for all matching service records.
+ TRAP( aError, RemoteSdpQueryL( iBDAddr, iRecHandleArray[ 0 ],
+ iRequestedAttrId ) );
+ }
+ else
+ {
+ // No matches, inform the client.
+ iQueryType = EQueryIdle;
+ iResultNotifier->ServiceAttributeSearchComplete( aHandle,
+ iAttrResArray,
+ aError );
+ }
+ }
+ else
+ {
+ // This was a ServiceSearch, inform our client of the result.
+ TInt recCount = iRecHandleArray.Count();
+ if( recCount > 0 )
+ {
+ // KErrEof is used to indicate no matching records.
+ aError = KErrNone;
+ }
+ iQueryType = EQueryIdle;
+ iResultNotifier->ServiceSearchComplete( iRecHandleArray, recCount,
+ aError );
+ }
+ }
+ NotifyError( aError );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MSdpAgentNotifier.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::AttributeRequestResult( TSdpServRecordHandle aHandle,
+ TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue )
+ {
+ TRACE_FUNC_ENTRY
+ // Ownership of CSdpAttrValue is passed here. Store the object so
+ // that the result array can point to string values rather than
+ // copy them (the object is anyway already constructed).
+ iAttrValArray.Append( aAttrValue );
+ iParser->SetAttributeID( aAttrID );
+ // Adds the attribute values synchronously to the result array.
+ TRAP_IGNORE( aAttrValue->AcceptVisitorL( *iParser ) );
+ (void) aHandle;
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MSdpAgentNotifier.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::AttributeRequestComplete( TSdpServRecordHandle aHandle,
+ TInt aError )
+ {
+ TRACE_FUNC_ENTRY
+ if( aError )
+ {
+ NotifyError( aError );
+ return;
+ }
+
+ if( iQueryType == EAttrQuery )
+ {
+ // This was a AttributeSearch, inform our client of the result.
+ iQueryType = EQueryIdle;
+ iResultNotifier->AttributeSearchComplete( aHandle, iAttrResArray, aError );
+ }
+ else if( iQueryType == EServiceAttrQuery )
+ {
+ TInt index = iRecHandleArray.Find( aHandle );
+ if( index <= KErrNotFound )
+ {
+ NotifyError( KErrCorrupt );
+ return;
+ }
+ // Pop the handle, since we don't need it anymore.
+ iRecHandleArray.Remove( index );
+ if( iRecHandleArray.Count() == 0 )
+ {
+ // This was the last result.
+ aError = KErrEof;
+ iQueryType = EQueryIdle;
+ }
+ iResultNotifier->ServiceAttributeSearchComplete( aHandle, iAttrResArray,
+ aError );
+ if( aError != KErrEof && iQueryType == EServiceAttrQuery )
+ {
+ // Request the attribute from the next matching record (if
+ // not cancelled in the callback, hence the check for the
+ // querytype) This will reset the attribute result array.
+ TRAP( aError, RemoteSdpQueryL( iBDAddr, iRecHandleArray[ 0 ],
+ iRequestedAttrId ) );
+ NotifyError( aError ); // Does nothing if there is no error.
+ }
+ }
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::NotifyError( TInt aError )
+ {
+ if( aError == KErrNone || aError == KErrEof || iResultNotifier == NULL )
+ {
+ return;
+ }
+ TSdpQueryType query = iQueryType;
+ iQueryType = EQueryIdle; // Need to set this before calling clients,
+ // as they may call us straight again.
+ if( query == EServiceQuery )
+ {
+ iResultNotifier->ServiceSearchComplete( RSdpRecHandleArray(), 0, aError );
+ }
+ else if( query == EAttrQuery )
+ {
+ iResultNotifier->AttributeSearchComplete( 0, RSdpResultArray(), aError );
+ }
+ if( query == EServiceAttrQuery )
+ {
+ iResultNotifier->ServiceAttributeSearchComplete( 0, RSdpResultArray(),
+ aError );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngSdpQuery::CheckSdpAgentL( const TBTDevAddr& aAddr )
+ {
+ if( !iSdpAgent || aAddr != iBDAddr )
+ {
+ delete iSdpAgent;
+ iSdpAgent = NULL;
+ iBDAddr = aAddr;
+ iSdpAgent = CSdpAgent::NewL( *this, iBDAddr );
+ }
+ else
+ {
+ iSdpAgent->Cancel();
+ }
+ if( iQueryType != EQueryIdle && iQueryType != EServiceAttrQuery )
+ {
+ // Another query is ongoing and has not been cancelled.
+ User::Leave( KErrInUse );
+ }
+ }