bluetoothmgmt/btmgr/BTManServer/RegistrySubSession.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Provides the implementation of the subsession that refers to remote devices
       
    15 // 
       
    16 //
       
    17 
       
    18 
       
    19 #include "BTManServer.h"
       
    20 #include "btmanserverutil.h"
       
    21 #include <bluetooth/logger.h>
       
    22 
       
    23 #ifdef __FLOG_ACTIVE
       
    24 _LIT8(KLogComponent, LOG_COMPONENT_BT_MANAGER_SERVER);
       
    25 #endif
       
    26 
       
    27 //=====================================================================
       
    28 //	CBTRegistrySubSession
       
    29 //=====================================================================
       
    30 //Description:	Provides an interface to the registry for device 
       
    31 //				This is needed to provide device connection information for
       
    32 //				subsequent connections.
       
    33 //=====================================================================
       
    34 
       
    35 
       
    36 CBTRegistrySubSession* CBTRegistrySubSession::NewL(CBTManSession& aSession, CBTRegistry& aRegistry)
       
    37 	{
       
    38 	LOG_STATIC_FUNC
       
    39 	CBTRegistrySubSession* self = new(ELeave) CBTRegistrySubSession(aSession, aRegistry);
       
    40 	//Since its a CObject derived class so we should use CleanupClosePushL
       
    41 	CleanupClosePushL(*self);	
       
    42 	self->ConstructL();
       
    43 	CleanupStack::Pop();
       
    44 	return self;
       
    45 	}
       
    46 
       
    47 void CBTRegistrySubSession::ConstructL()
       
    48 	{
       
    49 	LOG_FUNC
       
    50 	}
       
    51 	
       
    52 CBTRegistrySubSession::CBTRegistrySubSession(CBTManSession& aSession, CBTRegistry& aRegistry)
       
    53 : CBTManSubSession(aSession,aRegistry)
       
    54 	{
       
    55 	LOG_FUNC
       
    56 	}
       
    57 
       
    58 CBTRegistrySubSession::~CBTRegistrySubSession() 
       
    59 	{
       
    60 	LOG_FUNC
       
    61 	DoCloseView();
       
    62 	delete iResultBuffer;
       
    63 	}
       
    64 
       
    65 
       
    66 void CBTRegistrySubSession::OpenViewL(const TBTRegistrySearch& aSearch, const RMessage2& aMessage)
       
    67 /**
       
    68 	@param aSearch	The structure containing the parameters to search for
       
    69 	@param aMessage	The message to complete
       
    70 **/
       
    71 	{
       
    72 	LOG_FUNC
       
    73 	if (iDBView)
       
    74 		{
       
    75 		// previous view hasn't been retrieved
       
    76 		User::Leave(KErrInUse);
       
    77 		}
       
    78 
       
    79 	// Form the SQL query based on the search criteria
       
    80 	RBTDbQuery query;
       
    81 	CleanupClosePushL(query);
       
    82 	query.SearchL(aSearch);
       
    83 
       
    84 	// execute the SQL
       
    85 	iDBView = iRegistry.OpenViewL(query, iBookmark);
       
    86 
       
    87 	iUnderlyingSearch = query.ConstraintBuf().AllocL();
       
    88 
       
    89 	// see how many records are in the view
       
    90 	iViewCount = iDBView->CountL();
       
    91 
       
    92 	// send count back to client
       
    93 	if (!iViewCount)
       
    94 		{
       
    95 		User::Leave(KErrNotFound);
       
    96 		}
       
    97 	else
       
    98 		{
       
    99 		// go to the first record in the view for later retrieval
       
   100 		iDBView->FirstL();
       
   101 		iSession.CompleteMessage(aMessage, iViewCount);
       
   102 		}
       
   103 	CleanupStack::Pop(1); // query
       
   104 	// **leave view open for client's later requests upon it**
       
   105 	}
       
   106 
       
   107 void CBTRegistrySubSession::UnpairL(const TBTDevAddr& aAddress, const RMessage2& aMessage)
       
   108 /**
       
   109 	@param	aAddress	The address to unbond
       
   110 	@param	aMessage	The message to complete
       
   111 **/
       
   112 	{
       
   113 	LOG_FUNC
       
   114 	// Form the SQL query based on the device address
       
   115 	RBTDbQuery query;
       
   116 	CleanupClosePushL(query);
       
   117 	query.FindDeviceL(aAddress);
       
   118 
       
   119 	// Execute the SQL
       
   120 	RDbView* localView = iRegistry.OpenViewL(query, iBookmark);
       
   121 	CleanupCloseDeletePushL(localView);
       
   122 
       
   123 	HBufC* localViewUnderlyingSearch = query.ConstraintBuf().AllocLC();
       
   124 
       
   125 	TInt c = localView->CountL();
       
   126 	
       
   127 	if (c)
       
   128 		{
       
   129 		// device is there - check to see if client is allowed to change
       
   130 		__ASSERT_DEBUG(c==1, PanicServer(EBTManTooManyDevicesInView));
       
   131 
       
   132 		// Try to notify interested parties before deleting the device.
       
   133 		// If we notify afterwards, then the device will fall out of someone's
       
   134 		// view and a change would then not be detected on that view.
       
   135 		NotifyChange(*this, *localViewUnderlyingSearch);
       
   136 
       
   137 		// the client is allowed to change the details
       
   138 		iRegistry.UnpairL(*localView);
       
   139 		iSession.CompleteMessage(aMessage, KErrNone);
       
   140 		}
       
   141 	else
       
   142 		{
       
   143 		// device wasn't even there
       
   144 		User::Leave(KErrNotFound);
       
   145 		}
       
   146 		
       
   147 	// Cleanup localViewUnderlyingSearch, localView and query
       
   148 	CleanupStack::PopAndDestroy(3, &query);
       
   149 	}
       
   150 
       
   151 void CBTRegistrySubSession::GetDeviceL(const TBTNamelessDevice& aDevice, const RMessage2& aMessage)
       
   152 /**
       
   153 	Get a single nameless device from registry
       
   154 	@param	aDevice		The device to retrieve (only the address is used as a key at present)
       
   155 	@param	aMessage	The message to complete
       
   156 **/
       
   157 	{
       
   158 	LOG_FUNC
       
   159 	// open the device
       
   160 	TDbBookmark bookmark;
       
   161 	RDbView* localView = iRegistry.OpenDeviceL(aDevice.Address(), bookmark);
       
   162 	CleanupCloseDeletePushL(localView);
       
   163 
       
   164 	TInt localCount = localView->CountL();
       
   165 	
       
   166 	if (localCount==0)
       
   167 		{
       
   168 		// the device wasn't there!
       
   169 		User::Leave(KErrNotFound);
       
   170 		}
       
   171 	else
       
   172 		{
       
   173 		__ASSERT_DEBUG(localCount==1, PanicServer(EBTManTooManyDevicesInView));
       
   174 
       
   175 		// Get the resulting device (we take ownership), stays on cleanupstack
       
   176 
       
   177 
       
   178 		const TBTNamelessDevice* device =
       
   179 			iRegistry.GetNextNamelessDeviceLC(*localView,bookmark,aMessage.HasCapability(ECapabilityReadDeviceData));
       
   180 
       
   181 		
       
   182 		// Write back resulting device to client
       
   183 		TBTNamelessDevicePckgBuf writePckg;
       
   184 		writePckg = *device;
       
   185 
       
   186 		aMessage.WriteL(0, writePckg);
       
   187 		iSession.CompleteMessage(aMessage, KErrNone);
       
   188 		
       
   189 		CleanupStack::Pop(1);	// device
       
   190 		delete const_cast<TBTNamelessDevice*>(device);	//MSDev workaround
       
   191 		}
       
   192 	CleanupStack::PopAndDestroy(localView);
       
   193 	}
       
   194 
       
   195 
       
   196 void CBTRegistrySubSession::AddDeviceL(const CBTDevice& aDetails, const RMessage2& aMessage)
       
   197 /**
       
   198 	@note This is an insertion, which can be slower via SQL; so we stick with C++ methods
       
   199 	Further, this saves us the effort of converting various binary values into the ASCII
       
   200 	SQL equivalent, only for DBMS to have to retokenise it ;-)
       
   201 	Slight disadvantage is that the C++ interface to DBMS is synchronous...
       
   202 	..but the addition of a new row unordered should not be hard in our small database
       
   203 **/
       
   204 	{
       
   205 	LOG_FUNC
       
   206 
       
   207 	iRegistry.CreateDeviceL(aDetails,
       
   208 							aMessage.HasCapability(ECapabilityWriteDeviceData),
       
   209 							aMessage.SecureId());
       
   210 	// Form the SQL query based on the device address
       
   211 	RBTDbQuery query;
       
   212 	CleanupClosePushL(query);
       
   213 	query.FindDeviceL(aDetails.BDAddr());
       
   214 	
       
   215 	HBufC* localViewUnderlyingSearch = query.ConstraintBuf().AllocLC();
       
   216 
       
   217 	iSession.CompleteMessage(aMessage, KErrNone);
       
   218 
       
   219 	// Try to notify interested parties after adding the device.
       
   220 	// We need the device to be present in other views for change notification to work.
       
   221 	NotifyChange(*this, *localViewUnderlyingSearch);
       
   222 	
       
   223 	// Cleanup localViewUnderlyingSearch and query
       
   224 	CleanupStack::PopAndDestroy(2, &query);
       
   225 	}
       
   226 
       
   227 void CBTRegistrySubSession::ModifyL(const CBTDevice& aNewDetails, const RMessage2& aMessage)
       
   228 /**
       
   229 	@param	aNewDetails	The new device details; with the address to modify
       
   230 	@param	aMessage	The message to complete
       
   231 **/
       
   232 	{
       
   233 	LOG_FUNC
       
   234 	// check that we can modify this device...
       
   235 	if (!aNewDetails.IsValidBDAddr())
       
   236 		{
       
   237 		// the device address has not been set correctly
       
   238 		User::Leave(KErrCorrupt);
       
   239 		}
       
   240 
       
   241 	if (!iRegistry.DevicePresentL(aNewDetails.BDAddr()))
       
   242 		{
       
   243 		// the device record that the client wants to modify is not present in the registry
       
   244 		User::Leave(KErrNotFound);
       
   245 		}
       
   246 	else
       
   247 		{
       
   248 		// device is in Registry - open local device view
       
   249 		TDbBookmark dummy; // ignore position for now
       
   250 
       
   251 		// Form the SQL query based on the device address
       
   252 		RBTDbQuery query;
       
   253 		CleanupClosePushL(query);
       
   254 		query.FindDeviceL(aNewDetails.BDAddr());
       
   255 
       
   256 		// Execute the SQL
       
   257 		RDbView* localView = iRegistry.OpenViewL(query, dummy);
       
   258 		CleanupCloseDeletePushL(localView);
       
   259 
       
   260 		HBufC* localViewUnderlyingSearch = query.ConstraintBuf().AllocLC();
       
   261 	
       
   262 		// Try to notify interested parties before making the change.
       
   263 		// If we notify afterwards, then the device may fall out of someone's
       
   264 		// view and a change would then not be detected on that view.		
       
   265 		NotifyChange(*this, *localViewUnderlyingSearch);
       
   266 
       
   267 		iRegistry.UpdateDeviceL(*localView, aNewDetails); 
       
   268 		iSession.CompleteMessage(aMessage, KErrNone);
       
   269 	
       
   270 		// Cleanup localViewUnderlyingSearch, localView and query
       
   271 		CleanupStack::PopAndDestroy(3, &query);
       
   272 		}
       
   273 	}
       
   274 
       
   275 void CBTRegistrySubSession::ModifyL(const TBTNamelessDevice& aNewDetails, const RMessage2& aMessage)
       
   276 /**
       
   277 	@param	aNewDetails	The new device details; with the address to modify
       
   278 	@param	aMessage	The message to complete
       
   279 **/
       
   280 	{
       
   281 	LOG_FUNC
       
   282 	// make a CBTDevice based on the T class
       
   283 	CBTDevice* tempDevice = CBTDevice::NewLC(aNewDetails);
       
   284 	ModifyL(*tempDevice, aMessage);
       
   285 	CleanupStack::PopAndDestroy(tempDevice);
       
   286 	// Notification already handled by overloaded ModifyL() implementation
       
   287 	}
       
   288 
       
   289 void CBTRegistrySubSession::ModifyNameL(const TBTDevAddr& aAddress, const RMessage2& aMessage)
       
   290 /**
       
   291 	Updates one of the names for a device in the Registry
       
   292 	Here we decide if we can work with an address or not
       
   293 
       
   294 	@param	aAddress	The address of the device to modify
       
   295 	@param	aMessage	The message to complete, and from which we get the name
       
   296 **/
       
   297 	{
       
   298 	LOG_FUNC
       
   299 
       
   300 	// Form the SQL query based on the device address
       
   301 	RBTDbQuery query;
       
   302 	CleanupClosePushL(query);
       
   303 	query.FindDeviceL(aAddress);
       
   304 
       
   305 	// Execute the SQL
       
   306 	RDbView* localView = iRegistry.OpenViewL(query, iBookmark);
       
   307 	CleanupCloseDeletePushL(localView);
       
   308 
       
   309 	HBufC* localViewUnderlyingSearch = query.ConstraintBuf().AllocLC();
       
   310 
       
   311 	TInt c = localView->CountL();
       
   312 
       
   313 	if (!c)
       
   314 		{
       
   315 		// can't modify name cos device isn't there!
       
   316 		User::Leave(KErrNotFound);
       
   317 		}
       
   318 	
       
   319 	
       
   320 
       
   321 	// read the names
       
   322 	TBuf8<KMaxBluetoothNameLen> buf;
       
   323 	aMessage.ReadL(1, buf);
       
   324 	
       
   325 	// Try to notify interested parties before making the change.
       
   326 	// If we notify afterwards, then the device may fall out of someone's
       
   327 	// view and a change would then not be detected on that view.		
       
   328 	NotifyChange(*this, *localViewUnderlyingSearch);
       
   329 
       
   330 	// read out what's already in the database
       
   331 	iRegistry.UpdateNameL(aAddress, buf, static_cast<TBTManServerRequest>(aMessage.Function()));
       
   332 	// done, OK at this stage
       
   333 	iSession.CompleteMessage(aMessage, KErrNone);
       
   334 
       
   335 	// Cleanup localViewUnderlyingSearch, localView and query
       
   336 	CleanupStack::PopAndDestroy(3, &query);
       
   337 	}
       
   338 
       
   339 void CBTRegistrySubSession::PreLoadL(const RMessage2& aMessage)
       
   340 /**
       
   341 	Load in the results from DBMS
       
   342 	we'd have to load it all in at some time for giving to client, so we extend
       
   343 	the lifetime a bit.  We kill the cache upon delivery to client.
       
   344 	
       
   345 	This approach allows us to compute the size of the result set, 
       
   346 	so that we can tell client
       
   347 
       
   348 	@param	aMessage	The message to complete
       
   349 **/
       
   350 	{
       
   351 	LOG_FUNC
       
   352 	if (!iViewCount)
       
   353 		{
       
   354 		// client has asked for something we dont have
       
   355 		User::Leave(KErrNotFound);
       
   356 		}
       
   357 	
       
   358 	// In case a previous registry response is cancelled, and then for the next request, 
       
   359 	// a new registry response is created, the iResultBuffer could still be non-zero.
       
   360 	// So, release memory now.
       
   361 	delete iResultBuffer;
       
   362 	iResultBuffer = NULL;
       
   363 
       
   364 	// Create a buffer to hold the externalised entry
       
   365 	iResultBuffer = CBufFlat::NewL(sizeof(CBTDevice)); // just a granularity for expansion
       
   366 
       
   367 	RBufWriteStream stream;
       
   368 	CleanupClosePushL(stream);
       
   369 	stream.Open(*iResultBuffer);	// returns void
       
   370 
       
   371 	TInt res = KErrNone;
       
   372 	CBTDevice* device = NULL;
       
   373 
       
   374 	iNumDevicesInBuffer=0;
       
   375 	while (res == KErrNone)
       
   376 		{
       
   377 		// Get the entry and externalise to stream.
       
   378 		TRAP(res, 
       
   379 			 device= iRegistry.GetNextDeviceL(*iDBView, 
       
   380 									iBookmark, 
       
   381 									aMessage.HasCapability(ECapabilityReadDeviceData));
       
   382 			CleanupStack::PushL(device);
       
   383 			device->ExternalizeL(stream);
       
   384 			CleanupStack::PopAndDestroy(device);
       
   385 			device = NULL;
       
   386 			iNumDevicesInBuffer++;
       
   387 
       
   388 			);
       
   389 		}
       
   390 
       
   391 	// complete message with size of the blob or the error
       
   392 	TInt code;
       
   393 	if (res == KErrEof)
       
   394 		{
       
   395 		code = iResultBuffer->Size();
       
   396 		}
       
   397 	else
       
   398 		{
       
   399 		code = res;
       
   400 		}
       
   401 	iSession.CompleteMessage(aMessage, code);
       
   402 	CleanupStack::PopAndDestroy(1); // stream
       
   403 	
       
   404 	// do not need to close view here
       
   405 	}
       
   406 
       
   407 	
       
   408 void CBTRegistrySubSession::RetrieveL(const RMessage2& aMessage)
       
   409 /**
       
   410 	Returns the previously cached result set to the client
       
   411 
       
   412 	@param	aMessage	The message to complete
       
   413 **/
       
   414 	{
       
   415 	LOG_FUNC
       
   416 	if (!iResultBuffer)
       
   417 		{
       
   418 		// they haven't preloaded
       
   419 		User::Leave(KErrNotReady);
       
   420 		}
       
   421 	// write the buffer of devices back
       
   422 	aMessage.WriteL(0, iResultBuffer->Ptr(0));
       
   423 	iSession.CompleteMessage(aMessage, iNumDevicesInBuffer);
       
   424 
       
   425 	// release memory now to reduce footprint
       
   426 	delete iResultBuffer;
       
   427 	iResultBuffer = NULL;
       
   428 	}
       
   429 
       
   430 void CBTRegistrySubSession::DeleteViewL(const RMessage2& aMessage)
       
   431 /**
       
   432 	Deletes all devices in the view - could be used to delete many devices in one call
       
   433 
       
   434 	@param	aMessage The message to complete
       
   435 **/
       
   436 	{
       
   437 	LOG_FUNC
       
   438 	if (!iViewCount)
       
   439 		{
       
   440 		// no point calling delete on a view with no devices contained!
       
   441 		User::Leave(KErrNotReady);
       
   442 		}
       
   443 
       
   444 	// Try to notify interested parties before deleting devices.
       
   445 	// If we notify afterwards, then the devices will fall out of someone's
       
   446 	// view and a change would then not be detected on that view.
       
   447 	NotifyChange(*this, *iUnderlyingSearch);
       
   448 
       
   449 	//	Delete all in view only if client has W.D.D capability. Otherwise delete the
       
   450 	// devices whose SID value is same as the SecureId
       
   451 	iRegistry.DeleteViewL(	*iDBView, 
       
   452 							aMessage.HasCapability(ECapabilityWriteDeviceData),
       
   453 							aMessage.SecureId());
       
   454 
       
   455 
       
   456 	iSession.CompleteMessage(aMessage, KErrNone);
       
   457 	
       
   458 	// The view is not null, but probably not of much
       
   459 	// use (ie. a view containing devices created by processes other than your own)
       
   460 	// In addition, making the closure conditional would mean a potential SC
       
   461 	// break for code moving from non-secure to secure world, so DoCloseView
       
   462 	// remains non-optional at this point.
       
   463 	DoCloseView();
       
   464 	}
       
   465 
       
   466 void CBTRegistrySubSession::UnpairViewL(const RMessage2& aMessage)
       
   467 /**
       
   468 	Unpairs all devices in the view
       
   469 
       
   470 	@param	aMessage	The message to complete
       
   471 **/
       
   472 	{
       
   473 	LOG_FUNC
       
   474 	if (!iViewCount)
       
   475 		{
       
   476 		// no point calling delete on a view with no devices contained!
       
   477 		User::Leave(KErrNotReady);
       
   478 		}
       
   479 	
       
   480 	// Try to notify interested parties before making the change.
       
   481 	// If we notify afterwards, then the device may fall out of someone's
       
   482 	// view and a change would then not be detected on that view.		
       
   483 	NotifyChange(*this, *iUnderlyingSearch);
       
   484 		
       
   485 	iRegistry.UnpairViewL(*iDBView);
       
   486 	iSession.CompleteMessage(aMessage, KErrNone);
       
   487 	}
       
   488 	
       
   489 void CBTRegistrySubSession::CloseView(const RMessage2& aMessage)
       
   490 /**
       
   491 	Client has finished with the view
       
   492 	
       
   493 	@param	aMessage	The message to complete
       
   494 */
       
   495 	{
       
   496 	LOG_FUNC
       
   497 	DoCloseView();
       
   498 	iSession.CompleteMessage(aMessage, KErrNone);
       
   499 	
       
   500 	// no underlying registry change, so don't notify
       
   501 	}
       
   502 
       
   503 void CBTRegistrySubSession::DoCloseView()
       
   504 /**
       
   505 	Close the internal view if it exists
       
   506 **/
       
   507 	{
       
   508 	LOG_FUNC
       
   509 	if (iDBView)
       
   510 		{
       
   511 		iDBView->Close();
       
   512 		delete iDBView;
       
   513 		iDBView=NULL;
       
   514 
       
   515 		delete iUnderlyingSearch;
       
   516 		iUnderlyingSearch=NULL;
       
   517 		}
       
   518 	// No point having notify on closed view; yet session may have already processed a cancel on it
       
   519 	if (iSession.FindMessage(iViewChangeNotificationMessage))
       
   520 		{
       
   521 		iSession.CompleteMessage(iViewChangeNotificationMessage, KErrCompletion);
       
   522 		}
       
   523 
       
   524 	iViewCount=0;
       
   525 	}
       
   526 
       
   527 
       
   528 void CBTRegistrySubSession::Cleanup(TInt /*aError*/)
       
   529 	{
       
   530 	LOG_FUNC
       
   531 	// this subsession can help by closing the view
       
   532 	// it is unlikely to be in a good state anyway
       
   533 	DoCloseView();
       
   534 	}
       
   535 
       
   536 void CBTRegistrySubSession::NotifyChange(CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor)
       
   537 /**
       
   538 	Called by methods that know they've changed settings on the remotedevice table
       
   539 	This method will notify the client that was interested
       
   540 **/
       
   541 	{
       
   542 	LOG_FUNC
       
   543 	CBTManSubSession::NotifyChange(KRegistryChangeRemoteTable, aSubSessionViewOwner, aViewDescriptor);
       
   544 	}
       
   545 
       
   546 TBool CBTRegistrySubSession::IsOverlappingView(const TDesC& aViewDescriptor)
       
   547 	{
       
   548 	LOG_FUNC
       
   549 	// Need to take the view descriptor and test with our view
       
   550 	TBool match = EFalse;
       
   551 
       
   552 	// We cannot rely on the handle of iViewChangeNotificationMessage to provide an indicator
       
   553 	// of whether or not the message is completed, since we have a copy of the RMessage2 held by
       
   554 	// the CBTManMessage instance.
       
   555 	if (iDBView && iSession.FindMessage(iViewChangeNotificationMessage))
       
   556 		{
       
   557 		// Bookmark current place then use at end
       
   558 		TDbBookmark bookmark = iDBView->Bookmark();
       
   559 
       
   560 		// We never expect the following calls to iDBView methods to leave.
       
   561 		TInt findResult=KErrNotFound;
       
   562 #ifdef _DEBUG
       
   563 		TRAPD(err, 
       
   564 			iDBView->FirstL();
       
   565 			findResult = iDBView->FindL(RDbRowSet::EForwards, TDbQuery(aViewDescriptor));
       
   566 			);
       
   567 		__ASSERT_DEBUG(err == KErrNone, PanicServer(EBTManUnexpectedDbError));
       
   568 #else
       
   569 		iDBView->FirstL();
       
   570 		findResult = iDBView->FindL(RDbRowSet::EForwards, TDbQuery(aViewDescriptor));
       
   571 #endif
       
   572 
       
   573 		if (findResult != KErrNotFound)
       
   574 			{
       
   575 			match = ETrue;
       
   576 			iSession.CompleteMessage(iViewChangeNotificationMessage, KErrNone);
       
   577 			}
       
   578 			
       
   579 #ifdef _DEBUG
       
   580 		TRAP(err, iDBView->GotoL(bookmark));
       
   581 		__ASSERT_DEBUG(err == KErrNone, PanicServer(EBTManUnexpectedDbError));
       
   582 #else
       
   583 		iDBView->GotoL(bookmark);
       
   584 #endif
       
   585 		}
       
   586 
       
   587 	return match;
       
   588 	}
       
   589 
       
   590 /*virtual*/ void CBTRegistrySubSession::SetViewChangeNotificationMessage(const RMessage2& aMessage)
       
   591 	{
       
   592 	LOG_FUNC
       
   593 	if (iDBView)
       
   594 		{
       
   595 		iViewChangeNotificationMessage = aMessage;
       
   596 		// Complete later
       
   597 		}
       
   598 	else
       
   599 		{
       
   600 		iSession.CompleteMessage(aMessage, KErrNotReady);
       
   601 		}
       
   602 	}