pimprotocols/pbap/server/pbapfoldernodepb.cpp
changeset 0 e686773b3f54
equal deleted inserted replaced
-1:000000000000 0:e686773b3f54
       
     1 // Copyright (c) 2006-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 //
       
    15 
       
    16 #include <cntdb.h>
       
    17 
       
    18 #include "pbapfoldernodepb.h"
       
    19 #include "pbaprequest.h"
       
    20 #include "pbapfolderclient.h"
       
    21 #include "pbapexporter.h"
       
    22 #include "pbaperrorreporter.h"
       
    23 #include "pbapserver.h"
       
    24 #include "pbapappheader.h"
       
    25 
       
    26 #include "btaccesshostlog.h"
       
    27 
       
    28 // constants
       
    29 _LIT(KFolderPb, "pb");
       
    30 
       
    31 
       
    32 /*static*/ CFolderNodePb* CFolderNodePb::NewL(MVirtualFolderClient& aClient)
       
    33 	{
       
    34 	LOG_STATIC_FUNC
       
    35 	CFolderNodePb* self = new (ELeave) CFolderNodePb(aClient);
       
    36 	CleanupStack::PushL(self);
       
    37 	self->ConstructL();
       
    38 	CleanupStack::Pop(self);
       
    39 	return self;
       
    40 	}
       
    41 
       
    42 
       
    43 CFolderNodePb::CFolderNodePb(MVirtualFolderClient& aClient)
       
    44 : CFolderNode(aClient, KFolderPb())
       
    45 	{
       
    46 	LOG_FUNC
       
    47 	}
       
    48 
       
    49 		
       
    50 void CFolderNodePb::ConstructL()
       
    51 	{
       
    52 	LOG_FUNC
       
    53 	iHandleCache = CPbapPbHandleCache::NewL(iClient.ContactDB(), *this);
       
    54 	}
       
    55 
       
    56 
       
    57 CFolderNodePb::~CFolderNodePb()
       
    58 	{
       
    59 	LOG_FUNC
       
    60 
       
    61 	delete iHandleCache;
       
    62 	delete iAsyncExporter;		
       
    63 	delete iSearchResults;
       
    64 	iCacheIndexesToExport.Close();
       
    65 	}
       
    66 	
       
    67 	
       
    68 void CFolderNodePb::CancelGet()
       
    69 	{
       
    70 	LOG_FUNC
       
    71 	// cancel asynchronous searching and sorting of contacts
       
    72 	iClient.ContactDbViews().CancelSearchAndSortRequest();
       
    73 	
       
    74 	// cancel any asynchronous export operations and avoid iAsyncExporter is deleted
       
    75 	// by itself
       
    76 	CPbapPbExporter* tmpExporter = iAsyncExporter;
       
    77 	iAsyncExporter = NULL;
       
    78 	delete tmpExporter;
       
    79 	
       
    80 	// reset for next get request
       
    81 	Reset();
       
    82 	}
       
    83 
       
    84 void CFolderNodePb::GetComplete()
       
    85 	{
       
    86 	LOG_FUNC
       
    87 	
       
    88 	if (iAsyncExporter)
       
    89 		{
       
    90 		delete iAsyncExporter;
       
    91 		iAsyncExporter = NULL;
       
    92 		}
       
    93 	}
       
    94 
       
    95 
       
    96  void CFolderNodePb::Reset()
       
    97  	{
       
    98  	LOG_FUNC
       
    99 	
       
   100  	delete 	iSearchResults;
       
   101 	iSearchResults = NULL;
       
   102  
       
   103 	delete iAppHeader;
       
   104 	iAppHeader = NULL;
       
   105 	
       
   106 	iCacheIndexesToExport.Reset();	
       
   107  	}
       
   108  
       
   109  				
       
   110 TInt CFolderNodePb::DoGetItem(TInt aHandle)
       
   111 	{
       
   112 	LOG_FUNC
       
   113 	// check that state has been reset after previous get request
       
   114 	if(iAsyncExporter)
       
   115 		{
       
   116 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderPbExportAlreadyExists));
       
   117 		return KErrAlreadyExists;
       
   118 		}
       
   119 
       
   120 	TInt error = KErrNone;
       
   121 	TInt index = 0;
       
   122 				
       
   123 	if (iPhonebookChanged)
       
   124 		{
       
   125 		// the Pb phonebook has been modified since the last get request
       
   126 		// report precondition failed error to obex until next listing
       
   127 		// request completes (or new Pbap session initiated)
       
   128 		iClient.ErrorReporter().SendPreconditionFailedError();
       
   129 		// error already reported above so don't update error
       
   130 		
       
   131 		delete iAppHeader;
       
   132 		iAppHeader = NULL;
       
   133 		}
       
   134 	// search for the requested handle in the cache
       
   135 	else if ((index = iHandleCache->FindHandle(aHandle)) != KErrNotFound)
       
   136 		{
       
   137 		// export the contact associated with this handle
       
   138 		TRAP(error, iAsyncExporter = CPbapPbItemExporter::NewL(iClient, *this, *iHandleCache, index, 1, iAppHeader->VCardVersion(), iAppHeader->Filter()));
       
   139 		}
       
   140 	else 
       
   141 		{
       
   142 		// the handle does not exist must report not found error to Obex
       
   143 		iClient.ErrorReporter().SendNotFoundError();
       
   144 		// error already reported above so don't update error
       
   145 		
       
   146 		delete iAppHeader;
       
   147 		iAppHeader = NULL;
       
   148 		}
       
   149 	return error;
       
   150 	}
       
   151 
       
   152 
       
   153 TInt CFolderNodePb::DoGetListing()
       
   154 	{
       
   155 	LOG_FUNC
       
   156 	
       
   157 	TInt error = KErrNone;	
       
   158 	if (iAppHeader->SearchValue().Length() || iAppHeader->Order() != SymbianPBAP::EIndexed)
       
   159 		{
       
   160 		// search or non-indexed sort requested
       
   161 		TRAP(error, SearchAndSortItemsL());
       
   162 		}
       
   163 	else
       
   164 		{
       
   165 		// the order is indexed and no search was requested so export listing now
       
   166 		TRAP(error, ExportIndexSortedListingL());
       
   167 		}
       
   168 	
       
   169 	if (error != KErrNone)
       
   170 		{
       
   171 		// error occurred so reset state ready for next get request
       
   172 		Reset();
       
   173 		}
       
   174 	return error;	
       
   175 	}
       
   176 
       
   177 
       
   178 /**
       
   179  Use database views to search and sort contacts
       
   180 */
       
   181 void CFolderNodePb::SearchAndSortItemsL()
       
   182 	{
       
   183 	LOG_FUNC
       
   184 	if(iSearchResults)
       
   185 		{
       
   186 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderSearchInProgress));
       
   187 		User::Leave(KErrAlreadyExists);
       
   188 		}
       
   189 	
       
   190 	// The views only support alphabetical and phonetic sort orders so for index ordered
       
   191 	// searches use alphabetical order and then resort the results when search complete			
       
   192 	SymbianPBAP::TOrder order = (iAppHeader->Order() == SymbianPBAP::EIndexed ? SymbianPBAP::EAlphabetical : iAppHeader->Order());
       
   193 
       
   194 	// create empty array to store results
       
   195 	iSearchResults = CContactIdArray::NewL();
       
   196 				
       
   197 	// start the asynchronous search and sort				
       
   198 	iClient.ContactDbViews().GetContactIdsMatchingCriteriaL(order, iAppHeader->SearchAttribute(), iAppHeader->SearchValue(), *iSearchResults, *this);
       
   199 	}
       
   200 
       
   201 
       
   202 void CFolderNodePb::ExportIndexSortedListingL()
       
   203 	{
       
   204 	LOG_FUNC
       
   205 	// check that state has been reset after previous get request
       
   206 	if(iAsyncExporter)
       
   207 		{
       
   208 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderPbExportAlreadyExists));
       
   209 		User::Leave(KErrAlreadyExists);
       
   210 		}
       
   211 	
       
   212 	if(iCacheIndexesToExport.Count() != 0)
       
   213 		{
       
   214 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderCachedIndexes));
       
   215 		User::Leave(KErrAlreadyExists);
       
   216 		}
       
   217 	
       
   218 	// build an array of indexes to cache items (handle/contact Id pairs) to export.
       
   219 	// Since the cache is ordered on handle the indexes match the ordering of the cache
       
   220 
       
   221 	// determine the last handle to export and then start the append loop from iListStartOffset
       
   222 	TInt maxHandle = Min(iAppHeader->MaxListCount() + iAppHeader->ListStartOffset(), HandleCount());
       
   223 	for (TInt index = iAppHeader->ListStartOffset(); index < maxHandle; ++index)
       
   224 		{
       
   225 		iCacheIndexesToExport.AppendL(index);
       
   226 		}
       
   227 			
       
   228 	// export array of cache items as listing
       
   229 	iAsyncExporter = CPbapPbListingExporter::NewL(iClient, *this, *iHandleCache, iCacheIndexesToExport);
       
   230 	}
       
   231 
       
   232 
       
   233 TInt CFolderNodePb::DoGetCount()
       
   234 	{
       
   235 	LOG_FUNC
       
   236 	// check that state has been reset correctly
       
   237 	if(iAsyncExporter)
       
   238 		{
       
   239 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderPbExportAlreadyExists));
       
   240 		return KErrAlreadyExists;
       
   241 		}
       
   242 	
       
   243 	// export the Pb phonebook size. This is equal to the number of handles in the
       
   244 	// cache (assuming that 0.vcf is always counted even if no owner card is set)
       
   245 	TRAPD(error, iAsyncExporter = CPbapPbCountExporter::NewL(iClient, *this, HandleCount()));
       
   246 	return error;
       
   247 	}
       
   248 
       
   249 
       
   250 TInt CFolderNodePb::DoGetFolder()
       
   251 	{
       
   252 	LOG_FUNC
       
   253 	// check that state has been reset correctly
       
   254 	if(iAsyncExporter)
       
   255 		{
       
   256 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderPbExportAlreadyExists));
       
   257 		return KErrAlreadyExists;
       
   258 		}
       
   259 	
       
   260 	// setup range of items to export
       
   261 	TInt count = 0;
       
   262 	if (iAppHeader->ListStartOffset() < HandleCount())
       
   263 		{
       
   264 		// limit the number of items to export to the number of handles available from
       
   265 		// the offset
       
   266 		count = Min(iAppHeader->MaxListCount(), HandleCount() - iAppHeader->ListStartOffset());
       
   267 		}
       
   268 				
       
   269 	// export the contacts associated with range of handle cache indexes (these
       
   270 	// are aleady sorted in increasing handle order)
       
   271 	TRAPD(error, iAsyncExporter = CPbapPbItemExporter::NewL(iClient, *this, *iHandleCache, iAppHeader->ListStartOffset(), count, iAppHeader->VCardVersion(), iAppHeader->Filter()));
       
   272 	return error;
       
   273 	}
       
   274 
       
   275 
       
   276 void CFolderNodePb::HandleCacheChanged()
       
   277 	{
       
   278 	LOG_FUNC
       
   279 		
       
   280 	// the contact item a handle refers to has changed. All PullvCard requests will
       
   281 	// now be blocked until the next listing request (or session close)
       
   282 	iPhonebookChanged = ETrue;
       
   283 	// check to see if there is an export in progress
       
   284 	if (iSearchResults || iAsyncExporter)
       
   285 	
       
   286 		{
       
   287 		// cancel the export and report error according to the error reporting
       
   288 		// scheme for modified/deleted handles
       
   289 		CancelGet();
       
   290 		}
       
   291 	}
       
   292 
       
   293 
       
   294 void CFolderNodePb::HandleSearchAndSortComplete(TInt aError)
       
   295 	{
       
   296 	LOG_FUNC
       
   297 	
       
   298 	if (aError == KErrNone)
       
   299 		{
       
   300 		// sorting and searching completed successfully
       
   301 		TRAP(aError, ExportSearchAndSortResultsL());
       
   302 		}
       
   303 	
       
   304 	if (aError != KErrNone)
       
   305 		{
       
   306 		// get request failed report error to obex and reset
       
   307 		iClient.ErrorReporter().SendServiceUnavailableError();
       
   308 		Reset();
       
   309 		}
       
   310 	}
       
   311 
       
   312 
       
   313 void CFolderNodePb::ExportSearchAndSortResultsL()
       
   314 	{
       
   315 	LOG_FUNC	
       
   316 	
       
   317 	// check that state has been reset after previous get request
       
   318 	if(iAsyncExporter)
       
   319 		{
       
   320 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderPbExportAlreadyExists));
       
   321 		User::Leave(KErrAlreadyExists);
       
   322 		}
       
   323 	if(iCacheIndexesToExport.Count() != 0)
       
   324 		{
       
   325 		__ASSERT_DEBUG(EFalse, Panic(EVirtualFolderCachedIndexes));
       
   326 		User::Leave(KErrAlreadyExists);
       
   327 		}
       
   328 
       
   329 	TInt count = iSearchResults->Count();
       
   330 	
       
   331 	// if the order is indexed then to get here means that a search value has been specified
       
   332 	if (iAppHeader->Order() == SymbianPBAP::EIndexed)
       
   333 		{
       
   334 		// sort the search result into index order
       
   335 		RArray<TInt> sortedIndexes;
       
   336 		CleanupClosePushL(sortedIndexes);
       
   337 		for (TInt ii = 0; ii < count; ++ii)
       
   338 			{
       
   339 			TContactItemId contactId = (*iSearchResults)[ii];
       
   340 			TInt index = iHandleCache->FindContactId(contactId);
       
   341 			if (index != KErrNotFound)
       
   342 				{
       
   343 				// insert index in order to match handle ordering of cache
       
   344 				sortedIndexes.InsertInOrderL(index);
       
   345 				}
       
   346 			}
       
   347 		
       
   348 		// results array no longer required
       
   349 		delete iSearchResults;
       
   350 		iSearchResults = NULL;
       
   351 		
       
   352 		// extract range of cache indexes to export
       
   353 		count = Min(iAppHeader->MaxListCount() + iAppHeader->ListStartOffset(), sortedIndexes.Count());		
       
   354 		for (TInt jj = iAppHeader->ListStartOffset(); jj < count; ++jj)
       
   355 			{
       
   356 			iCacheIndexesToExport.AppendL(sortedIndexes[jj]);
       
   357 			}
       
   358 		CleanupStack::PopAndDestroy(); // sortedIndexes	
       
   359 		}
       
   360 	// to get here means it's a non-index order sort or search
       
   361 	else
       
   362 		{
       
   363 		// the search results array is sorted in the correct (alphabetic or
       
   364 		// phonetic) order. Build array of indexes of cache items which match the
       
   365 		// contact ids 
       
   366 		TInt maxAndOffset = iAppHeader->MaxListCount() + iAppHeader->ListStartOffset();
       
   367 		count = Min(count, maxAndOffset);
       
   368 		
       
   369 		// decide whether there is a OwnCard
       
   370 		TBool hasOwnCard = ETrue;
       
   371 		TInt ownCardItemIndex = iHandleCache->FindHandle(KOwnCardHandle); // always present
       
   372 		TContactItemId contactId = iHandleCache->ContactIdAtL(ownCardItemIndex);
       
   373 		if(contactId == KNullContactId)
       
   374 			{
       
   375 			hasOwnCard = EFalse;
       
   376 			}
       
   377 
       
   378 		// fill the array iCacheIndexsToExport
       
   379 		for (TInt ii = iAppHeader->ListStartOffset(); ii < count; ++ii)
       
   380 			{
       
   381 			TContactItemId contactId = (*iSearchResults)[ii];
       
   382 			TInt index = iHandleCache->FindContactId(contactId);
       
   383 			if (index!=KErrNotFound)
       
   384 				{
       
   385 				iCacheIndexesToExport.AppendL(index);
       
   386 				}
       
   387 			}
       
   388 
       
   389 		// append an empty own card (0.vcf) when doing sorting on alphabetic or phonetic order
       
   390 		// search value should be empty when doing sorting
       
   391 		if(iAppHeader->SearchValue().Size() == 0 && !hasOwnCard)
       
   392 			{
       
   393 			// "count < maxAndOffset" means that 
       
   394 			// "iSearchResults->Count()" < "iAppHeader->MaxListCount() + iAppHeader->ListStartOffset()" 
       
   395 			// in which case, we need to append an empty OwnCard entry to iCacheIndexesToExport.
       
   396 			if(count < maxAndOffset)
       
   397 				{
       
   398 				iCacheIndexesToExport.AppendL(KOwnCardHandle);
       
   399 				}
       
   400 			}
       
   401 		// results array no longer required
       
   402 		delete iSearchResults;
       
   403 		iSearchResults = NULL;			
       
   404 		}
       
   405 		
       
   406 	// export items associated with list of handle cache indexes
       
   407 	iAsyncExporter = CPbapPbListingExporter::NewL(iClient, *this, *iHandleCache, iCacheIndexesToExport);
       
   408 	}
       
   409 
       
   410 
       
   411  void CFolderNodePb::HandleExportComplete(TInt aError)
       
   412  	{
       
   413  	LOG_FUNC
       
   414  		
       
   415  	if (aError)
       
   416  		{
       
   417  		if(iPhonebookChanged)
       
   418  			{
       
   419 	 		iClient.ErrorReporter().SendPreconditionFailedError();
       
   420  			}
       
   421  		else
       
   422  			{
       
   423 	 		// error occured during export report service unavailable error to obex 
       
   424 	 		iClient.ErrorReporter().SendServiceUnavailableError();
       
   425  			}
       
   426  		}
       
   427  	
       
   428  	// a successful listing request allows the pb phonebook to be read from again
       
   429  	// after it has been modified
       
   430  	if (aError == KErrNone && iAppHeader->Operation() == EPullVCardListing)
       
   431  		{
       
   432  		iPhonebookChanged = EFalse;
       
   433  		}
       
   434  		
       
   435  	// get request complete	so reset state ready for next one
       
   436  	Reset();
       
   437  	}
       
   438 
       
   439 
       
   440  TInt CFolderNodePb::HandleCount()
       
   441  	{
       
   442  	return iHandleCache->Count();
       
   443  	}
       
   444