messagingfw/msgsrvnstore/server/src/cmsvconverterwaiter.cpp
changeset 22 bde600d88860
child 35 f8ad95794a08
child 40 320ec5cd0227
equal deleted inserted replaced
21:08008ce8a6df 22:bde600d88860
       
     1 // Copyright (c) 2007-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 
       
    17 /**
       
    18 HEADER FILES
       
    19  */
       
    20 
       
    21 #include "cmsvconverterwaiter.h"
       
    22 #include "cmessageconvertermanager.h"
       
    23 
       
    24 //const
       
    25 const TUid KUidMsvIndexFile = {0x10003C6B};
       
    26 
       
    27 static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy);
       
    28 // literals
       
    29 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
    30 	_LIT(KMessagingDBName, "\\messaging.db");
       
    31 #else
       
    32 	_LIT(KMessagingDBName,"[1000484B]messaging.db");
       
    33 #endif
       
    34 
       
    35 
       
    36 
       
    37 // static class initialiser
       
    38 CMsvConverterWaiter* CMsvConverterWaiter::iConverterWaiter = NULL;
       
    39 
       
    40 
       
    41 /**
       
    42 Instance()
       
    43 The function returns already created instance of
       
    44 this class to the caller. To create a new instance
       
    45 the caller should call InstanceL(). 
       
    46 @return CMsvConverterWaiter* : An instance of converter waiter.
       
    47 */ 
       
    48 CMsvConverterWaiter* CMsvConverterWaiter::Instance()
       
    49 	{
       
    50 	return iConverterWaiter;
       
    51 	}
       
    52 
       
    53 /**
       
    54 InstanceL()
       
    55 Instatiates converter waiter object.It is responsible for initiating and completing 
       
    56 message store conversion
       
    57 
       
    58 @param aServer: Message Server Object
       
    59 @return CMsvConverterWaiter* : An instance of converter waiter.
       
    60 */
       
    61 CMsvConverterWaiter* CMsvConverterWaiter::InstanceL(CMsvServer* aServer)
       
    62 	{
       
    63 	if(iConverterWaiter == NULL)
       
    64 		{
       
    65 		CMsvConverterWaiter* self = new(ELeave)CMsvConverterWaiter(aServer);
       
    66 		iConverterWaiter = self;
       
    67 		}
       
    68 
       
    69 	return iConverterWaiter;	
       
    70 	}
       
    71 
       
    72 /**
       
    73 ~CMsvConverterWaiter()
       
    74  
       
    75 @param None
       
    76 @return: None
       
    77 @internalComponent
       
    78  */
       
    79 CMsvConverterWaiter::~CMsvConverterWaiter()
       
    80 	{
       
    81 	iConverterWaiter = NULL;
       
    82 	Cancel();
       
    83 	iConverterQueue.Close();
       
    84 	iConverterThread.Close();
       
    85 	// Free the handle to the property
       
    86 	iProperty.Close();
       
    87 	}
       
    88 
       
    89 /*
       
    90 CMsvConverterWaiter()
       
    91 Default constructor. Adds this active request into active scheduler queue.
       
    92    
       
    93 @param aServer: messaging server
       
    94 @param iActive: active object
       
    95 @internalComponent
       
    96 */
       
    97 CMsvConverterWaiter::CMsvConverterWaiter(CMsvServer* aServer)
       
    98 : CActive(EPriorityLow),iServer(aServer)
       
    99 	{ 
       
   100 	CActiveScheduler::Add(this); 
       
   101 	}
       
   102 
       
   103 /**
       
   104 DoCancel()
       
   105 Stub Code
       
   106 
       
   107 @param : None
       
   108 @return: None
       
   109 */
       
   110 void CMsvConverterWaiter::DoCancel()
       
   111 	{
       
   112 	}
       
   113 
       
   114 /**
       
   115 DefineProperty()
       
   116 Define the property and attached it.
       
   117 
       
   118 @param none.
       
   119 @return void.
       
   120 */
       
   121 TInt CMsvConverterWaiter::DefineProperty()
       
   122 	{
       
   123 	// Define the property and create a handle to it
       
   124 	TInt err = RProperty::Define(KMyPropertyCat, KMyPropertyName,RProperty::EInt,KAllowAllPolicy,KAllowAllPolicy);
       
   125 	if(!err)
       
   126 		{
       
   127 		iProperty.Attach(KMyPropertyCat,KMyPropertyName,EOwnerThread);
       
   128 		}
       
   129 	return err;
       
   130 	}
       
   131 
       
   132 /**
       
   133 PublishProperty()
       
   134 Publishing property.
       
   135 
       
   136 @param aValue : value will published.
       
   137 @return void.
       
   138 */
       
   139 TInt CMsvConverterWaiter::PublishProperty(TInt aValue)
       
   140 	{
       
   141 	TInt err = iProperty.Set(aValue);	
       
   142 	return err;
       
   143 	}
       
   144 
       
   145 
       
   146 /**
       
   147 RunL()
       
   148 Asynchronous request handler of an active object. 
       
   149 Invoked when a notification is received from the converter thread.
       
   150 Upon succesful conversion, this removes the index file , drive from the queue and closes 
       
   151 the converter thread.
       
   152 When the conversion is cancelled , it removes the partially converted database table fro headers
       
   153 and completes the conversion request with KErrCancel.
       
   154 
       
   155 @param None
       
   156 @return: None
       
   157 @internalComponent
       
   158 */
       
   159 void CMsvConverterWaiter::RunL()
       
   160 	{
       
   161 	if(iStatus >= KErrNone)
       
   162 		{
       
   163 		//Update drive status for this drive. EMsvMessageStoreAvailableStatus
       
   164 		iServer->UpdateDriveStatusL(TDriveUnit(iConverterQueue[0].iDriveNumber),EMsvMessageStoreAvailableStatus);
       
   165 		
       
   166 		//Close the existing handle to the thread
       
   167 		
       
   168 		
       
   169 		//Complete this request
       
   170 		Completed(KErrNone);
       
   171 		iConverterThread.Close(); 
       
   172 		}
       
   173 	else if(iStatus == KErrCancel)	
       
   174 		{
       
   175 		// we would have published this property so we can safely delte it in case of cancel
       
   176 		RProperty::Delete(KMyPropertyCat,KMyPropertyName);
       
   177 				
       
   178 		iConverterThread.Close(); 
       
   179 		
       
   180 		// The previous conversion request failed
       
   181 		Completed(iStatus.Int());	
       
   182 		}
       
   183 	else
       
   184 		{
       
   185 		// The previous conversion request failed
       
   186 		iConverterThread.Close(); 
       
   187 		Completed(iStatus.Int());
       
   188 		}
       
   189 
       
   190 	// start conversion for the next drive in the queue
       
   191 	if(iConverterQueue.Count())
       
   192 		{
       
   193 		StartMessageStoreConversionL(iConverterQueue[0].iMessage,ETrue);
       
   194 		}
       
   195 	}
       
   196 
       
   197 /**
       
   198 StartMessageStoreConversionL()
       
   199 Starts the message store conversion.
       
   200 Steps:
       
   201 1. validates the drive.
       
   202 2. Creates a RThread object for conversion.
       
   203 3. Logons to the created thread to receive notofications.
       
   204 4. Resumes the converter thread and starts message store conversion.
       
   205 5. Marks this request as active. 
       
   206 
       
   207 @param aMessage: RMessage2 representing client request and containing request data.
       
   208 @param aQueuedRequest: Boolean flag specifying if the drive is queued.
       
   209 @return: None
       
   210 @internalComponent
       
   211 */
       
   212 void CMsvConverterWaiter::StartMessageStoreConversionL(const RMessage2& aMessage,TBool aQueuedRequest)
       
   213 	{
       
   214 	_LIT(KConverterThread,"StartMessageStoreConversion");
       
   215 	
       
   216 	TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0();
       
   217 	TInt error = KErrNone;	
       
   218 	
       
   219 	//This is a new request, we need to validate this. 
       
   220 	//Note : the drive is already validated if it is in the queue.
       
   221 	if(!aQueuedRequest)
       
   222 		{
       
   223 		error = ValidateRequestedDriveL(driveNumber);		
       
   224 		}
       
   225 		
       
   226 	if(error == KErrNone) // if proper
       
   227 		{
       
   228 		if(!aQueuedRequest) // if it is not already queued
       
   229 			{
       
   230 			TConversionQueue request;
       
   231 			request.iDriveNumber = driveNumber;
       
   232 			request.iMessage = aMessage;
       
   233 			iConverterQueue.Append(request);
       
   234 			}
       
   235 	
       
   236 		iDriveNumber = driveNumber;
       
   237 		TAny* conversionStatus = &iDriveNumber;
       
   238 	
       
   239 		TInt err = iConverterThread.Create(KConverterThread, &CMessageConverterManager::StartConversion,KDefaultStackSize*8,KMinHeapSize,0x8000000,conversionStatus,EOwnerThread);
       
   240 		
       
   241 		iStatus = KRequestPending;
       
   242 		if(!err)
       
   243 			{
       
   244 			iConverterThread.Logon(iStatus);
       
   245 			iConverterThread.Resume();
       
   246 			}
       
   247 		// activate this request
       
   248 		SetActive();
       
   249 		}
       
   250 	else
       
   251 		{
       
   252 		// complete this request with the right error
       
   253 		aMessage.Complete(error);			
       
   254 		}
       
   255 		
       
   256 	}
       
   257 
       
   258 /**
       
   259 QueueConversionRequestL()
       
   260 Queues conversion request for a drive. A drive is queued for conversion when conversion is 
       
   261 currently in progress for a drive.
       
   262 
       
   263 @param aMessage: RMessage2 representing client request and containing request data.
       
   264 @return: None
       
   265 @internalComponent
       
   266 */
       
   267 void CMsvConverterWaiter::QueueConversionRequestL(const RMessage2& aMessage)
       
   268 	{
       
   269 	TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0();
       
   270 	
       
   271 	TInt pos = 0;
       
   272 	TBool found = EFalse;	
       
   273 	while(pos < iConverterQueue.Count())
       
   274 		{
       
   275 		if(iConverterQueue[pos++].iDriveNumber == driveNumber )// drive not in the queue
       
   276 			{
       
   277 			found = ETrue;
       
   278 			}
       
   279 		}
       
   280 		
       
   281 	if(found)
       
   282 		{
       
   283 		aMessage.Complete(KErrAlreadyExists);
       
   284 		}
       
   285 	else
       
   286 		{
       
   287 		TInt error = ValidateRequestedDriveL(driveNumber);
       
   288 		if(error == KErrNone)
       
   289 			{
       
   290 			//validation fine. Add this request
       
   291 			TConversionQueue request;
       
   292 			request.iDriveNumber = driveNumber;
       
   293 			request.iMessage = aMessage;
       
   294 			iConverterQueue.Append(request);
       
   295 			}
       
   296 		else
       
   297 			{
       
   298 			aMessage.Complete(error);
       
   299 			}
       
   300 		}
       
   301 	}
       
   302 
       
   303 /**
       
   304 ValidateRequestedDriveL()
       
   305 Validates the message store in the requested drive.
       
   306 It checks for the following conditions.
       
   307 1) Drive is present in preferred drive list.
       
   308 2) The drive is already present in conversion Queue.
       
   309 3) Checks if the version 1 message store is present 
       
   310 4) Identifies if version 0 message store is corrupt..
       
   311 
       
   312 @param aDrive: Drive number.
       
   313 @return: None
       
   314 @internalComponent
       
   315 */
       
   316 TInt CMsvConverterWaiter::ValidateRequestedDriveL(TDriveNumber aDrive)
       
   317 	{
       
   318 	// check if the drive is present in preferred drive list		
       
   319 	TInt error = ValidateDriveInPreferredDriveListL(aDrive);
       
   320 	if(error != KErrNone)
       
   321 		{
       
   322 		return error;
       
   323 		}
       
   324 
       
   325 	// Check if Version 1 message store exists. 
       
   326 	TParse parse;
       
   327 	TPtrC drive = TDriveUnit(aDrive).Name();
       
   328 	parse.Set(KMessagingDBName, &drive, NULL);
       
   329 	TFileName dbFileName = parse.FullName();
       
   330 	
       
   331 	// check version 1 message store
       
   332 	RSqlDatabase temp;
       
   333 	CleanupClosePushL(temp);
       
   334 	
       
   335 	error = temp.Open(dbFileName);
       
   336 	
       
   337 	temp.Close();
       
   338 	CleanupStack::PopAndDestroy();  // temp
       
   339 	
       
   340 	//Version 1 message store may be corrupt
       
   341 	if(error == KSqlErrCorrupt )
       
   342 		{
       
   343 		return error;
       
   344 		}
       
   345 	
       
   346 	//version 1 does not exist, check version 0 is corrupt
       
   347 	if(error == KErrNotFound) 
       
   348 		{
       
   349 		TBuf<KMaxPath> filePath;
       
   350 		TPtrC drive(TDriveUnit(aDrive).Name());
       
   351 		filePath.Append(drive);
       
   352 		filePath.Append(KIndexFilePath);
       
   353 		
       
   354 		RFs ifsSession;
       
   355 		User::LeaveIfError(ifsSession.Connect()); 
       
   356 		
       
   357 		RFile file;
       
   358 		TInt error = file.Open(ifsSession, filePath, EFileShareAny|EFileWrite);
       
   359 		
       
   360 		if(error==KErrNone)
       
   361 			{
       
   362 			CPermanentFileStore* iIndexStore = CPermanentFileStore::FromL(file);
       
   363 			CleanupStack::PushL(iIndexStore);
       
   364 			if (iIndexStore->Type() != TUidType(KPermanentFileStoreLayoutUid, KUidMsvIndexFile))
       
   365 				{
       
   366 				User::Leave(KErrCorrupt);	
       
   367 				}
       
   368 			CleanupStack::PopAndDestroy(); // iIndexStore
       
   369 			}
       
   370 		ifsSession.Close();
       
   371 		file.Close();
       
   372 		}
       
   373 	return KErrNone;
       
   374 	}
       
   375 
       
   376 /**
       
   377 isRunningMessageStoreConverter()
       
   378 Checks if converter waiter is active and waiting for completion of a conversion request. 
       
   379 	
       
   380 @param None
       
   381 @return: Boolean flag specifying if the conversion is in progress,i,e if this active object is busy.
       
   382 @internalComponent
       
   383 */
       
   384 TBool CMsvConverterWaiter::isRunningMessageStoreConverter()
       
   385 	{
       
   386 	if( iStatus == KRequestPending )
       
   387 		{
       
   388 		return ETrue;
       
   389 		}
       
   390 	else
       
   391 		{
       
   392 		return EFalse;
       
   393 		}
       
   394 	}
       
   395 
       
   396 /**
       
   397 CancelConversionL()
       
   398 Cancels conversion for a drive.
       
   399 Steps to cancel.
       
   400 1. Stop converter Thread.
       
   401 2. Remove the partially converted header table.
       
   402 3. Complete the asynchronous request for conversion of the drive.
       
   403 4. Remove The drive from the drive array.
       
   404 5. If more drives are found in the queue, than initiate conversion for the next drive.
       
   405 
       
   406 @param aMessage: RMessage2 representing client request and containing request data.
       
   407 @return None
       
   408 @internalComponent
       
   409 */	
       
   410 void CMsvConverterWaiter::CancelConversionL(const RMessage2& aMessage)
       
   411 	{
       
   412 	//Get the drive
       
   413 	TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0();
       
   414 	
       
   415 	TInt pos = 0;
       
   416 	TBool found = EFalse;
       
   417 	while(pos < iConverterQueue.Count())
       
   418 		{
       
   419 		if(iConverterQueue[pos].iDriveNumber == driveNumber)
       
   420 			{
       
   421 			found = ETrue;
       
   422 			break;
       
   423 			}
       
   424 		else
       
   425 			{
       
   426 			pos++;
       
   427 			}
       
   428 		}
       
   429 		
       
   430 	if(pos == 0 && found)// this is the active request
       
   431 		{
       
   432 		// Define cancel property 
       
   433 		TInt err = DefineProperty();	
       
   434 		if(err == KErrNone)
       
   435 			{
       
   436 			// published the property so that, conversion thread will releases the memory and return.
       
   437 			PublishProperty(KErrCancel);
       
   438 			aMessage.Complete(KErrNone);
       
   439 			}
       
   440 		else
       
   441 			{
       
   442 			aMessage.Complete(err);
       
   443 			}
       
   444 		}
       
   445 	else if(found)// this drive is queued
       
   446 		{
       
   447 		aMessage.Complete(KErrNone);
       
   448 		iConverterQueue[pos].iMessage.Complete(KErrCancel);
       
   449 		iConverterQueue.Remove(pos);
       
   450 		}
       
   451 	else// invalid rive for cancellation
       
   452 		{
       
   453 		aMessage.Complete(KErrNotFound);
       
   454 		}
       
   455 	}
       
   456 
       
   457 /**
       
   458 GetConversionStatus()
       
   459 Returns conversion status for a drive.
       
   460 
       
   461 @param aMessage: RMessage handle.
       
   462 @return None
       
   463 @internalComponent
       
   464 */	
       
   465 void CMsvConverterWaiter::GetConversionStatus(const RMessage2& aMessage)
       
   466 	{
       
   467 	TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0();
       
   468 	TInt pos = 0;
       
   469 	TBool found = EFalse;
       
   470 	while(pos < iConverterQueue.Count())
       
   471 		{
       
   472 		if(iConverterQueue[pos++].iDriveNumber == driveNumber)
       
   473 			{
       
   474 			found = ETrue;
       
   475 			}
       
   476 		}
       
   477 	if(found)
       
   478 		{
       
   479 		if (pos == 0)
       
   480 			{
       
   481 			aMessage.Complete(0); // This request is active
       
   482 			}
       
   483 		else
       
   484 			{
       
   485 			aMessage.Complete(1); // Drive is queued for conversion
       
   486 			}
       
   487 		}
       
   488 	else
       
   489 		{
       
   490 		aMessage.Complete(-1);	// drive not found
       
   491 		}
       
   492 	}
       
   493 	
       
   494 
       
   495 /**
       
   496 Completed()
       
   497 Completes the asynchronous request for message store conversion for the completed drive.
       
   498 When conversion completes successfully, it gets notified of the completion. 
       
   499 The active conversion is alwasys the first element on the conversion queue.
       
   500 Upon compeltion, the first element in the queue gets compeleted.and the drive is removed
       
   501 from the drive array.
       
   502 
       
   503 @param aStatus: MTM ID of the table.
       
   504 @return None
       
   505 @internalComponent
       
   506 */	
       
   507 void CMsvConverterWaiter::Completed(const TInt aStatus)
       
   508 	{
       
   509 	iConverterQueue[0].iMessage.Complete(aStatus);
       
   510 	iConverterQueue.Remove(0);
       
   511 	
       
   512 	}
       
   513 
       
   514 /**
       
   515 ValidateDriveInPreferredDriveListL()
       
   516 Validates a drive by checking if it is present in preferred drive list and its ststus is
       
   517 EMsvMessageStoreNotSupportedStatus
       
   518 Also checks if the drive is already queued for conversion and as such is a duplicate request.
       
   519 
       
   520 @param aDrive: Drive number.
       
   521 @return None
       
   522 @internalComponent
       
   523 */
       
   524 TInt CMsvConverterWaiter::ValidateDriveInPreferredDriveListL(TDriveNumber aDrive)
       
   525 	{
       
   526 	CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
       
   527 	RArray<TDriveNumber> driveNumList;
       
   528 	CleanupClosePushL(driveNumList);
       
   529 	TInt index;
       
   530 	for(index=0; index<driveList->Count(); index++)
       
   531 		{
       
   532 		if(EMsvMessageStoreNotSupportedStatus == (*driveList)[index].status)
       
   533 			{
       
   534 			driveNumList.AppendL((*driveList)[index].driveNum);		
       
   535 			}
       
   536 		}
       
   537 	
       
   538 	if( driveNumList.Find(aDrive) != KErrNotFound)
       
   539 		{
       
   540 		CleanupStack::PopAndDestroy();  // driveNumList
       
   541 		return KErrNone;
       
   542 		}
       
   543 	CleanupStack::PopAndDestroy();  // driveNumList
       
   544 	return KErrNotFound;
       
   545 	}