messagingfw/msgsrvnstore/server/src/MSVSERV.CPP
changeset 62 db3f5fa34ec7
child 35 f8ad95794a08
child 47 d176b53f330f
equal deleted inserted replaced
60:9f5ae1728557 62:db3f5fa34ec7
       
     1 // Copyright (c) 2000-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 // MSVSERV.CPP
       
    15 //
       
    16 
       
    17 #ifdef _DEBUG
       
    18 #undef _NO_SERVER_LOGGING_
       
    19 #endif
       
    20 
       
    21 #include <e32std.h>
       
    22 
       
    23 #include <barsc.h>
       
    24 #include <barsread.h>
       
    25 #pragma warning( disable : 4245 )
       
    26 #include <bautils.h>
       
    27 #pragma warning( default : 4245 )
       
    28 #include <bafindf.h>
       
    29 #include <u32std.h>
       
    30 #include <msgs.rsg>
       
    31 
       
    32 #include "MSVSTD.H"
       
    33 #include "MSVIPC.H"
       
    34 #include "MSVIDS.H"
       
    35 #include "MSVUIDS.H"
       
    36 #include "MSVRUIDS.H"
       
    37 #include "MTSR.H"
       
    38 #include "MSVENTRY.H"
       
    39 #include "MSERVER.H"
       
    40 #include "MSVRBLD.H"
       
    41 #include "MSVSERV.H"
       
    42 #include "MSVDELET.H"
       
    43 #include "MSVMOVE.H"
       
    44 #include "MSVUTILS.H"
       
    45 #include "MSVPANIC.H"
       
    46 #include "MSVAPI.H"
       
    47 #include "indexcontext.h"
       
    48 #include "CMsvCachedStore.h"
       
    49 #include "CMsvBackupHandler.h"
       
    50 #include "cmsvmailinitwaiter.h"
       
    51 #include "TMsvServerStoreManager.h"
       
    52 #include "msvsearchsortcachemanager.h"
       
    53 #include "msvsearchsortdeltacache.h"
       
    54 
       
    55 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
       
    56 #include "cinstalledmtmgroup.h"
       
    57 #include "msvconsts.h"			  
       
    58 #endif
       
    59 
       
    60 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
    61 	#include "centralrepository.h"
       
    62 	#include "cmsvdiskchangenotifier.h"
       
    63 	
       
    64 	const TInt KMaxDriveSupported=7;
       
    65 	const TInt KUidConifgFileValue = 0x10286a26;
       
    66 	const TUid KUidConfigFile = {KUidConifgFileValue};
       
    67 	const TInt KCenRepCurrentDriveKey=10;
       
    68 	
       
    69 	#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
    70 		_LIT(KPreferredDriveListFilePath, "C:\\private\\1000484b\\msgprioritydrivelist.ini");
       
    71 	#else
       
    72 		_LIT(KPreferredDriveListFilePath, "z:\\private\\1000484b\\msgprioritydrivelist.ini");
       
    73 	#endif		  // #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE) 
       
    74 #endif	  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
    75 
       
    76 const TInt KMsvMtmOpsQueueGranularity=8;
       
    77 const TInt KMsvMtmOpsQueueArrayGranularity=4;
       
    78 const TInt KMsvMtmOpsSessionIdArrayGranularity=4;
       
    79 
       
    80 _LIT(KRomMtmDataFilePath, ":\\RESOURCE\\MESSAGING\\MTM\\");
       
    81 _LIT(KMsvStoreInitFileName, "StoreInit.tmp");
       
    82 _LIT(KMsvPostInitialisationExe, "z:\\sys\\bin\\MailInit.exe");
       
    83 
       
    84 #ifdef MSG_SERV_AUTO_CLOSE
       
    85 // the server closes after the last session closes
       
    86 const TInt KMsvCloseTime=0x200000; // approx 2 seconds
       
    87 const TInt KMsvInitCloseTime=0xA00000; // approx 10 seconds
       
    88 #endif
       
    89 
       
    90 // the time between the attempts at writing hidden streams and removing emntries
       
    91 const TInt KMsvDelayTime=0x00A00000; // approx 10 seconds
       
    92 const TUid KMsvMailInitExeUid={0x10004849};
       
    93 const TUint msgServerPolicyRangeCount = 22;
       
    94 const TInt msgServerPolicyRanges[msgServerPolicyRangeCount] =
       
    95 	{
       
    96 	0,  //  EAlwaysPass	 -> EMsvGetEntry				 -> ReadEntryData
       
    97 //  1,	  EAlwaysPass	 -> EMsvGetChildren			  -> Filtered
       
    98 //  2,	  EAlwaysPass	 -> EMsvGetRemainingChildren
       
    99 	3,  //  Test			-> EMsvLockEntry
       
   100 //  4,	  Test			-> EMsvReleaseEntry
       
   101 	5,  //  PanicClient	 -> EMsvMakeFileDirectory
       
   102 	6,  //  EAlwaysPass	 -> EMsvChangeEntry			  -> ModifyEntryData
       
   103 //  7,	  EAlwaysPass	 -> EMsvCreateEntry			  -> CreateEntry
       
   104 //  8,	  EAlwaysPass	 -> EMsvDeleteEntries			-> ModifyEntryData
       
   105 //  9,	  EAlwaysPass	 -> EMsvMoveEntries			  -> MoveEntries
       
   106 //  10,	 EAlwaysPass	 -> EMsvCopyEntries			  -> CopyEntries
       
   107 //  11,	 EAlwaysPass	 -> EMsvNotifySessionEvent
       
   108 //  12,	 EAlwaysPass	 -> EMsvCancelSessionEventNotification
       
   109 //  13,	 EAlwaysPass	 -> EMsvReadStore				-> ReadEntryData
       
   110 //  14,	 EAlwaysPass	 -> EMsvLockStore				-> ModifyEntryData
       
   111 //  15,	 EAlwaysPass	 -> EMsvReleaseStore			 -> ModifyEntryData
       
   112 	16, //  PanicClient	 -> EMsvCommittedStore
       
   113 	17, //  Deprecated	  -> EMsvLocalStoreDeleted
       
   114 	18, //  EAlwaysPass	 -> EMsvOperationData
       
   115 //  19,	 EAlwaysPass	 -> EMsvCommandData
       
   116 //  20,	 EAlwaysPass	 -> EMsvCancelOperation
       
   117 //  21,	 EAlwaysPass	 -> EMsvOperationProgress
       
   118 //  22,	 EAlwaysPass	 -> EMsvOperationCompletion
       
   119 //  23,	 EAlwaysPass	 -> EMsvOperationMtm
       
   120 //  24,	 EAlwaysPass	 -> EMsvMtmCommand			   -> MTMTransferCommand
       
   121 //  25,	 EAlwaysPass	 -> EMsvFillRegisteredMtmDllArray
       
   122 	26, //  WriteDeviceData -> EMsvInstallMtmGroup
       
   123 //  25,	 WriteDeviceData -> EMsvDeInstallMtmGroup
       
   124 	28, //  EAlwaysPass	 -> EMsvUseMtmGroup
       
   125 //  29,	 EAlwaysPass	 -> EMsvReleaseMtmGroup
       
   126 //  30,	 EAlwaysPass	 -> EMsvGetMtmGroupData
       
   127 	31, //  WriteDeviceData -> EMsvCloseServer
       
   128 	32, //  EAlwaysPass	 -> EMsvStopService			  -> StopService
       
   129 //  33,	 EAlwaysPass	 -> EMsvServiceActive
       
   130 //  34,	 EAlwaysPass	 -> EMsvServiceProgress
       
   131 //  35,	 EAlwaysPass	 -> EMsvRemoveEntry			  -> ModifyEntryData
       
   132 	36, //  PanicClient	 -> EMsvCreatedStore
       
   133 	37, //  EAlwaysPass	 -> EMsvGetMessageDirectory
       
   134 //  38,	 EAlwaysPass	 -> EMsvSlotAvailable
       
   135 //  39,	 EAlwaysPass	 -> EMsvSetSessionAsObserver
       
   136 	40, //  Test			-> EMsvSetFailure
       
   137 	41, //  EWriteUserData  -> EMsvChangeAttributes
       
   138 	42, //  EAlwaysPass	 -> EMsvGetChildIds
       
   139 	43, //  WriteDeviceData -> EMsvChangeDrive
       
   140 	44, //  EAlwaysPass	 -> EMsvOutstandingOperations
       
   141 //  45,	 EAlwaysPass	 -> EMsvGetNotifySequence
       
   142 	46, //  Deprecated	  -> EMsvGetMtmPath
       
   143 //  47,	 Deprecated	  -> EMsvSetMtmPath
       
   144 //  48,	 Deprecated	  -> EMsvDelMtmPath
       
   145 	49, //  EAlwaysPass	 -> EMsvSetReceiveEntryEvents
       
   146 //  50,	 EAlwaysPass	 -> EMsvDecStoreReaderCount	  -> ReadEntryData
       
   147 //  51,	 EAlwaysPass	 -> EMsvGetMessageDrive
       
   148 //  52,	 EAlwaysPass	 -> EMsvGetMtmRequiredCapabilities
       
   149 //  53,	 EAlwaysPass	 -> EMsvCreateAttachmentForWrite -> ModifyEntryData
       
   150 //  54,	 EAlwaysPass	 -> EMsvOpenAttachment		   -> ReadEntryData
       
   151 //  55,	 EAlwaysPass	 -> EMsvOpenAttachmentForWrite   -> ModifyEntryData
       
   152 //  56,	 EAlwaysPass	 -> EMsvDeleteAttachment		 -> ModifyEntryData
       
   153 //  57,	 EAlwaysPass	 -> EMsvOpenFileStoreForRead	 -> ReadEntryData
       
   154 //  58,	 EAlwaysPass	 -> EMsvOpenTempStoreFile		-> ModifyEntryData
       
   155 //  59,	 EAlwaysPass	 -> EMsvReplaceFileStore		 -> ModifyEntryData
       
   156 //  60,	 EAlwaysPass	 -> EMsvDeleteFileStore		  -> ModifyEntryData
       
   157 //  61,	 EAlwaysPass	 -> EMsvFileStoreExists
       
   158 //  62,	 EAlwaysPass	 -> EMsvGetAndClearIndexCorruptFlag
       
   159 		63,	// EWriteDeviceData		  -> EMsvCopyStore
       
   160 //	  64,	// EWriteDeviceData		  -> EMsvDeleteStore
       
   161 	65	 // EAlwaysPass			 -> EMsvDriveContainsStore
       
   162 //  66,	 EAlwaysPass	 -> EMsvMessageStoreDrivePresent
       
   163 //  67,	 EAlwaysPass	 -> EMsvFileExists
       
   164 //  68,	 EAlwaysPass	 -> EMsvRenameAttachment		 -> ModifyEntryData
       
   165 //  69,	 EAlwaysPass	 -> EMsvReplaceAttachmentForWrite -> ModifyEntryData
       
   166 //  70,	 EAlwaysPass	 -> EMsvGetAttachmentFilePath
       
   167 //  71,	 EAlwaysPass	 -> EMsvOperationSystemProgress
       
   168 //  72,	 EAlwaysPass	 -> EMsvGetNonOperationMtmData
       
   169 	};
       
   170 
       
   171 enum TMsvSecurityPolicy
       
   172 	{
       
   173 	EMsvSecurityWriteDeviceData	 = 0,
       
   174 	EMsvSecurityWriteUserData	   = 1,
       
   175 	EMsvSecurityPanicClient		 = 2,
       
   176 	EMsvSecurityTestCapabilities	= 3
       
   177 	};
       
   178 
       
   179 const TInt KMsvDeprecationPolicy	= EMsvSecurityPanicClient;
       
   180 const TInt KMsvTestPolicy		   = EMsvSecurityTestCapabilities;
       
   181 
       
   182 const TUint8 msgServerPolicyElementsIndex[] =
       
   183 	{
       
   184 	CPolicyServer::EAlwaysPass,	 // applies to req 0-2
       
   185 	KMsvTestPolicy,				 // applies to req 3-4
       
   186 	EMsvSecurityPanicClient,		// applies to req 5
       
   187 	CPolicyServer::EAlwaysPass,	 // applies to req 6-15
       
   188 	EMsvSecurityPanicClient,		// applies to req 16
       
   189 	KMsvDeprecationPolicy,		  // applies to req 17
       
   190 	CPolicyServer::EAlwaysPass,	 // applies to req 18-25
       
   191 	EMsvSecurityWriteDeviceData,	// applies to req 26-27
       
   192 	CPolicyServer::EAlwaysPass,	 // applies to req 28-30
       
   193 	EMsvSecurityWriteDeviceData,	// applies to req 31
       
   194 	CPolicyServer::EAlwaysPass,	 // applies to req 32-35
       
   195 	EMsvSecurityPanicClient,		// applies to req 36
       
   196 	CPolicyServer::EAlwaysPass,	 // applies to req 37-39
       
   197 	KMsvTestPolicy,				 // applies to req 40
       
   198 	EMsvSecurityWriteUserData,	  // applies to req 41
       
   199 	CPolicyServer::EAlwaysPass,	 // applies to req 42
       
   200 	EMsvSecurityWriteDeviceData,	// applies to req 43
       
   201 	CPolicyServer::EAlwaysPass,	 // applies to req 44-45
       
   202 	KMsvDeprecationPolicy,		  // applies to req 46-48
       
   203 	CPolicyServer::EAlwaysPass,	 // applies to req 49-62
       
   204 	EMsvSecurityWriteDeviceData,			// applies to req 63-64
       
   205 	CPolicyServer::EAlwaysPass	  // applies to req 65
       
   206 	};
       
   207 
       
   208 const CPolicyServer::TPolicyElement msgServerPolicyElements[] =
       
   209 	{
       
   210 	// Check Write Device Data	  -> EMsvSecurityWriteDeviceData  = 0
       
   211 	{_INIT_SECURITY_POLICY_C1(ECapabilityWriteDeviceData), CPolicyServer::EFailClient},
       
   212 	// Check Write User Data		-> EMsvSecurityWriteUserData	= 1
       
   213 	{_INIT_SECURITY_POLICY_C1(ECapabilityWriteUserData), CPolicyServer::EFailClient},
       
   214 	// Panic the client			 -> EMsvSecurityPanicClient	  = 2
       
   215 	{_INIT_SECURITY_POLICY_FAIL, CPolicyServer::EPanicClient},
       
   216 	// Check for message server caps-> EMsvSecurityTestCapabilities = 3
       
   217 	{_INIT_SECURITY_POLICY_C7(ECapabilityReadDeviceData, ECapabilityWriteDeviceData, ECapabilityProtServ, ECapabilityNetworkControl, ECapabilityNetworkServices, ECapabilityLocalServices, ECapabilityReadUserData), CPolicyServer::EFailClient}
       
   218 	};
       
   219 
       
   220 const CPolicyServer::TPolicy msgServerPolicy =
       
   221 	{
       
   222 	CPolicyServer::EAlwaysPass,
       
   223 	msgServerPolicyRangeCount,
       
   224 	msgServerPolicyRanges,
       
   225 	msgServerPolicyElementsIndex,
       
   226 	msgServerPolicyElements
       
   227 	};
       
   228 
       
   229 
       
   230 //**********************************
       
   231 // CMsvMtmOperationList
       
   232 //**********************************
       
   233 
       
   234 CMsvMtmOperationQueue::CMsvMtmOperationQueue(TUid aMtmUid, TMsvId aServiceId)
       
   235 : CArrayPtrFlat<CMsvMtmOperation>(KMsvMtmOpsQueueGranularity),
       
   236 	iMtmUid(aMtmUid), iServiceId(aServiceId),
       
   237 	iSessionIdArray(KMsvMtmOpsSessionIdArrayGranularity)
       
   238 	{
       
   239 	__DECLARE_NAME(_S("CMsvMtmOperationQueue"));
       
   240 	}
       
   241 
       
   242 CMsvMtmOperationQueue::~CMsvMtmOperationQueue()
       
   243 	{
       
   244 	delete iMtm;
       
   245 	}
       
   246 
       
   247 
       
   248 //**********************************
       
   249 //CMsvServer
       
   250 //**********************************
       
   251 
       
   252 
       
   253 CMsvServer::CMsvServer(TInt aPriority, TBool aDebug)
       
   254 :   CPolicyServer(aPriority, msgServerPolicy), iSessionNumber(1), iMtmOperationQueueArray(KMsvMtmOpsQueueArrayGranularity), iDebug(aDebug), iReleasedForRestore(EFalse)
       
   255 //
       
   256 //
       
   257 //
       
   258 	{
       
   259 	}
       
   260 
       
   261 
       
   262 CMsvServer::~CMsvServer()
       
   263 //
       
   264 //
       
   265 //
       
   266 	{
       
   267 #ifndef _NO_SERVER_LOGGING_
       
   268 	Log(_L("Message Server closing"));
       
   269 #endif
       
   270 
       
   271 	__ASSERT_DEBUG(iMtmOperationQueueArray.Count()==0, PanicServer(EMsvSomeMtmQueueActive));
       
   272 	iMtmOperationQueueArray.ResetAndDestroy();
       
   273 
       
   274 	delete iMtmRegControl;
       
   275 	delete iServerMtmReg;
       
   276 #ifdef MSG_SERV_AUTO_CLOSE
       
   277 	delete iCloseTimer;
       
   278 #endif
       
   279 	delete iDelayTimer;
       
   280 	delete iBackup;
       
   281 	delete iContext;
       
   282 	delete iNewContext;
       
   283 	delete iBulkCreationSelection;
       
   284 	delete iMailinitWaiter;
       
   285 	delete iBulkChangeSelection;
       
   286 
       
   287 #ifndef _NO_SERVER_LOGGING_
       
   288 	if (iLog.LogValid())
       
   289 		iLog.CloseLog();
       
   290 	iLog.Close();
       
   291 #endif
       
   292 
       
   293 
       
   294 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   295 	// Destroy the notification objects.
       
   296 	TInt notifierCount = iNotifier.Count();
       
   297 	delete iDriveList;
       
   298 	
       
   299 	for(TInt index = 0; index < notifierCount; ++index)
       
   300 		{
       
   301 		iNotifier[index]->Cancel();
       
   302 		}
       
   303 
       
   304 	iNotifier.ResetAndDestroy();
       
   305 #else
       
   306 	delete iNotify;
       
   307 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   308 
       
   309 	delete iFreePoolInstance;
       
   310 
       
   311 	//iManager and iDeltacache deltetion.
       
   312 	delete iSearchSortCacheManager;
       
   313 
       
   314 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
   315 	delete iMessageDBAdapter;
       
   316 	
       
   317 	CMsvConverterWaiter *waiter = CMsvConverterWaiter::Instance();
       
   318 	if(waiter != NULL)
       
   319 		delete waiter;
       
   320 	
       
   321 #endif
       
   322 	iFs.Close();
       
   323 	iProtectedFolders.Reset();
       
   324 	}
       
   325 
       
   326 
       
   327 
       
   328 
       
   329 EXPORT_C CMsvServer* CMsvServer::NewL()
       
   330 	{
       
   331 	return CMsvServer::NewL(ETrue);
       
   332 	}
       
   333 
       
   334 
       
   335 
       
   336 CMsvServer* CMsvServer::NewL(TBool aDebug)
       
   337 	{
       
   338 	CMsvServer *pS = new(ELeave) CMsvServer(EPriority, aDebug);
       
   339 	CleanupStack::PushL(pS);
       
   340 	pS->ConstructL();
       
   341 	CleanupStack::Pop();
       
   342 	return pS;
       
   343 	}
       
   344 
       
   345 
       
   346 
       
   347 void CMsvServer::ConstructL()
       
   348 	{
       
   349 	// First start the server
       
   350 	StartL(KMsvServerName);
       
   351 
       
   352 	// conect to the file system
       
   353 	User::LeaveIfError(iFs.Connect());
       
   354 	TChar driveChar= iFs.GetSystemDriveChar();
       
   355 
       
   356 	iSystemDrive.Append(driveChar);
       
   357 	iSystemDrive.Append(KDriveDelimiter);
       
   358 #ifdef MSG_SERV_AUTO_CLOSE
       
   359 	iCloseTimer = CMsvTimer::NewL(*this, ETrue);
       
   360 	iCloseTimer->After(KMsvInitCloseTime);
       
   361 #endif
       
   362 	iDelayTimer = CMsvTimer::NewL(*this, EFalse);
       
   363 
       
   364 	iBulkCreationSelection = new(ELeave)CMsvEntrySelection();
       
   365 	iBulkChangeSelection = new(ELeave)CMsvEntrySelection();
       
   366 
       
   367 	iMailinitWaiter=CMsvMailinitWaiter::NewL(*this);
       
   368 
       
   369 // Code changes for 557.
       
   370 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   371 	// Create the preferred drive list.
       
   372 	CreatePreferredDriveListL();
       
   373 	
       
   374 	// Create notifiers for the appropriate drives.
       
   375 	TInt driveCount = iDriveList->Count(); 
       
   376 	TDriveUnit driveValue;
       
   377 	
       
   378 	// Create the notification objects for each drive in
       
   379 	// the preferred drive list. These objects will notify
       
   380 	// message server about the activity (media insertion/
       
   381 	// removal) in their respective drive.
       
   382 	for(TInt i = 0;i < driveCount; ++i)
       
   383 		{
       
   384 		driveValue = TDriveUnit((*iDriveList)[i].driveNum);
       
   385 		CMsvDiskChangeNotifier* diskChangeNotifier = CMsvDiskChangeNotifier::NewL(driveValue, *this);
       
   386 		User::LeaveIfError(iNotifier.Append(diskChangeNotifier));
       
   387 		}
       
   388 #else
       
   389 	iNotify = new(ELeave)CMsvNotifyDiskChange(iFs, *this);
       
   390 #endif	  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   391 
       
   392 	
       
   393 #ifndef _NO_SERVER_LOGGING_
       
   394 	CreateLogL();
       
   395 #endif
       
   396 
       
   397 	// Populate the protected folders list - currently only has the outbox, and
       
   398 	// also the remote services are protected.
       
   399 	User::LeaveIfError(iProtectedFolders.Append(KMsvGlobalOutBoxIndexEntryId));
       
   400 	iRemoteServicesProtected = ETrue;
       
   401 
       
   402 	// create the registry
       
   403 	CreateRegistriesL();
       
   404 
       
   405 	// set the file session and CMsvServer objects in TMsvServerStoreManager
       
   406 	iServerStoreManager.SetMsvServerAndFileSession(*this,iFs);
       
   407 
       
   408 	// Code change for PREQ 1189.
       
   409 	// 1. Create free pool
       
   410 	iFreePoolInstance = CMsvEntryFreePool::CreateL();
       
   411 	
       
   412 
       
   413 	// construct the index
       
   414 	// (it used to be done in CMsvServer::DoNewSessionL when the first session
       
   415 	// was being opened but we want to perform the full initialisation of
       
   416 	// the Message Server before starting the watchers)
       
   417 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   418 	CreateIndexL();
       
   419 	// Search Sort cache manager
       
   420 	iSearchSortCacheManager= CMSvSearchSortCacheManager::CreateManagerL(*this);
       
   421 	// Construct Search Sort cache Table
       
   422 	CreateSearchSortCacheL();
       
   423 	UpdateRepositoryL();
       
   424 #else
       
   425 	// Search Sort cache manager
       
   426 	iSearchSortCacheManager= CMSvSearchSortCacheManager::CreateManagerL(*this);
       
   427 	CreateIndexL(iDebug);
       
   428 #endif
       
   429 
       
   430 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
   431 	// Creating message DB adapter to access message header and body.
       
   432 	iMessageDBAdapter = CMsvMessageDBAdapter::NewL(IndexAdapter().GetDbAdapter());
       
   433 #endif
       
   434 
       
   435 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
   436 	iNotification = EMsvNullNotification;
       
   437 #endif
       
   438 	}
       
   439 
       
   440 void CMsvServer::CreateSearchSortCacheL()
       
   441 	{
       
   442 	iContext->IndexAdapter()->GetDbAdapter()->ConstructSortTableL();
       
   443 	iContext->IndexAdapter()->GetDbAdapter()->InitializeSortTableL();
       
   444 	}
       
   445 	
       
   446 	
       
   447 void CMsvServer::CreateRegistriesL()
       
   448 //
       
   449 // Create the MTM registry and control
       
   450 //
       
   451 	{
       
   452 	iServerMtmReg = CServerMtmDllRegistry::NewL(iFs);
       
   453 	iMtmRegControl = CMtmRegistryControl::NewL(iFs, *iServerMtmReg);
       
   454 	
       
   455 	TFileName filename;
       
   456 	TChar driveLetter;
       
   457 
       
   458 	TEntry entry;	   
       
   459 	TDriveList driveList;
       
   460 	User::LeaveIfError(iFs.DriveList(driveList));
       
   461 
       
   462 	for(TInt drive=0;drive< KMaxDrives; ++drive)
       
   463 		{
       
   464 		if (driveList[drive] == 0)
       
   465 			{
       
   466 			continue;
       
   467 			}
       
   468 		User::LeaveIfError(iFs.DriveToChar(drive,driveLetter));
       
   469 		filename.Zero();
       
   470 		filename.Append(driveLetter);
       
   471 		filename.Append(KRomMtmDataFilePath);
       
   472 		
       
   473 		// scan for any mtm data files and try to load them
       
   474 		if (iFs.Entry(filename, entry)==KErrNone)  
       
   475 			{
       
   476 			CDir* filelist=NULL;
       
   477 			if (iFs.GetDir(filename, KEntryAttNormal|KEntryAttAllowUid, ESortByName, filelist)==KErrNone)
       
   478 				{
       
   479 				CleanupStack::PushL(filelist);  
       
   480 				TInt i=filelist->Count();
       
   481 				TParse fileEntry;
       
   482 				TPtrC entryName;
       
   483 				//check we have files
       
   484 				if(i>0)
       
   485 					{
       
   486 					//get the first entry to be dealt with and register it
       
   487 					i--;
       
   488 					entry=(*filelist)[i];
       
   489 					fileEntry.Set(entry.iName,NULL,NULL);
       
   490 					entryName.Set(fileEntry.Name());
       
   491 
       
   492 					while(i>=0)
       
   493 						{
       
   494 						filename.Zero();
       
   495 						filename.Append(driveLetter);
       
   496 						filename.Append(KRomMtmDataFilePath);
       
   497 						filename.Append(entry.iName);
       
   498 						TUid mtmtypeuid;
       
   499 
       
   500 						// Use the file most appropriate to the current language
       
   501 						BaflUtils::NearestLanguageFile(iFs, filename);
       
   502 
       
   503 	#if defined (_DEBUG)
       
   504 						TInt err = iMtmRegControl->InstallMtmGroup(filename, mtmtypeuid);
       
   505 						iFs.Entry(filename, entry);
       
   506 						__ASSERT_DEBUG(err==KErrNone || err==KErrAlreadyExists || !((entry[0]==KPermanentFileStoreLayoutUid) && (entry[1]==KUidMsvDataComponent)), PanicServer(EMsvBadMtmDatFile));
       
   507 	#else
       
   508 						iMtmRegControl->InstallMtmGroup(filename, mtmtypeuid); // ignore the error
       
   509 	#endif
       
   510 						//search for the next entry with a different filename
       
   511 						while(i--)
       
   512 							{
       
   513 							TPtrC prevEntry=fileEntry.Name();
       
   514 							//get next entry
       
   515 							entry=(*filelist)[i];
       
   516 							TParse nextFileEntry;
       
   517 							nextFileEntry.Set(entry.iName,NULL,NULL);
       
   518 							entryName.Set(nextFileEntry.Name());
       
   519 							if(entryName.Compare(prevEntry)!=0)
       
   520 								{
       
   521 								//different filename
       
   522 								break;
       
   523 								}
       
   524 							}
       
   525 						}
       
   526 					}
       
   527 				CleanupStack::PopAndDestroy();
       
   528 				}
       
   529 			}
       
   530 		}
       
   531 		
       
   532 	}
       
   533 
       
   534 
       
   535 
       
   536 
       
   537 // Code change for PREQ 557.
       
   538 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   539 
       
   540 /**
       
   541  * CreateIndexL()
       
   542  *
       
   543  * Creates the index context. This will create the index
       
   544  * cache and related objects.
       
   545  */
       
   546 EXPORT_C void CMsvServer::CreateIndexL()
       
   547 	{
       
   548 	__ASSERT_DEBUG(iNewContext == NULL, PanicServer(EMsvNewContextExists));
       
   549 
       
   550 	// Create the new context.
       
   551 	iNewContext = CMsvIndexContext::NewL(*this, *this);
       
   552 	iStartupState = EMsvNullNotification;
       
   553 
       
   554 	// Creating the index cache.
       
   555 	iNewContext->CreateIndexL();
       
   556 	
       
   557 	// Updating the current drive number.
       
   558 	TUint curDriveIndex = iDriveList->CurrentDriveIndex();
       
   559 	iIndexDrive = (*iDriveList)[curDriveIndex].driveNum;
       
   560 	}
       
   561 
       
   562 
       
   563 
       
   564 
       
   565 // The context has completed successfully or with failure
       
   566 void CMsvServer::ContextComplete(TInt aError, TBool aRunMailInit)
       
   567 	{
       
   568 #ifndef _NO_SERVER_LOGGING_
       
   569 	Log(_L("Context complete with error %d"), aError);
       
   570 #endif
       
   571 
       
   572 	if (!aError)
       
   573 		{
       
   574 		for(TInt index = 0; index < iNotifier.Count(); ++index)
       
   575 			{
       
   576 			iNotifier[index]->Cancel();
       
   577 			}
       
   578 
       
   579 		iContext = iNewContext;
       
   580 		iNewContext = NULL;
       
   581 		
       
   582 #ifndef _NO_SERVER_LOGGING_
       
   583 		Log(_L("Deleting iBackup"));
       
   584 #endif
       
   585 
       
   586 		if(iBackup == NULL)
       
   587 			{
       
   588 			// To Gracefully handle and to register with the backup server.
       
   589 			TRAP_IGNORE(iBackup=CMsvBackupHandler::NewL(*this));
       
   590 			}
       
   591 
       
   592 		// Run mailinit.
       
   593 		TUint unused;
       
   594 		iFs.SetSessionToPrivate(iDriveList->CurrentDriveNumber());
       
   595 		TBool initNotCompleted = (iFs.Att(KMsvStoreInitFileName, unused)!=KErrNotFound);
       
   596 		if ((initNotCompleted || aRunMailInit))
       
   597 			{
       
   598 			RunMailInitExe(iDriveList->CurrentDriveNumber());
       
   599 			}
       
   600 
       
   601 		// Send index ready notification
       
   602 		NotifyChanged(EMsvIndexLoaded);	 
       
   603 		// Reset the index error state
       
   604 		iContext->IndexAdapter()->SetErrorState(KErrNone);
       
   605 		iStartupState = EMsvNullNotification;
       
   606 	
       
   607 		// Restart disk change notifications.
       
   608 		if(iContext)
       
   609 			{
       
   610 			for(TInt index = 0; index < iNotifier.Count(); ++index)
       
   611 				{
       
   612 				iNotifier[index]->Start();
       
   613 				}
       
   614 			}
       
   615 		}	   // if (!aError)
       
   616 
       
   617 	// Remember the error
       
   618 	iLoadError = aError;
       
   619 	}
       
   620 
       
   621 
       
   622 
       
   623 
       
   624 /**
       
   625  * ChangeDrive()
       
   626  * @param TInt: DriveNumber of the new current drive.
       
   627  * @param TRequestStatus: Request Status.
       
   628  * @return TInt: System wide error code.
       
   629  *
       
   630  * The function changes the message server current drive to the
       
   631  * drive specified as its first argument. The function implementation
       
   632  * is changed in PREQ 557. The function now assumes that the new 
       
   633  * current drive is already present in the preferred drive list. The 
       
   634  * client should ensure this before calling ChangeDrive().
       
   635  */
       
   636 EXPORT_C TInt CMsvServer::ChangeDrive(TInt aDrive, TRequestStatus* aStatus)
       
   637 	{
       
   638 	__ASSERT_ALWAYS(iContext->State() == TMsvIndexLoadProgress::EIndexComplete, PanicServer(EMsvLoadingInProgress));
       
   639 
       
   640 	TRAPD(err, DoChangeDriveL(aDrive, aStatus));
       
   641 	return err;
       
   642 	}
       
   643 	
       
   644 	
       
   645 	
       
   646 void CMsvServer::DoChangeDriveL(TInt aDrive, TRequestStatus* aStatus)
       
   647 	{
       
   648 	if(aDrive == iIndexDrive)
       
   649 		{
       
   650 		User::Leave(KErrNotSupported);
       
   651 		}
       
   652 	
       
   653 	if(aStatus)
       
   654 		{
       
   655 		*aStatus = KRequestPending; 
       
   656 		}
       
   657 	
       
   658 	// Check if the drive is present in the preferred drive list.
       
   659 	TInt newCurrentDriveIndex = 0;
       
   660 	TBool isDriveFound = EFalse;
       
   661 	for(; newCurrentDriveIndex < CMsvPreferredDriveList::GetDriveList()->Count(); newCurrentDriveIndex++)
       
   662 		{
       
   663 		if(aDrive == (*iDriveList)[newCurrentDriveIndex].driveNum)
       
   664 			{
       
   665 			isDriveFound = ETrue;
       
   666 			break;
       
   667 			}
       
   668 		}
       
   669 	
       
   670 	// The new drive is not already present in the preferred drive list.
       
   671 	if(!isDriveFound)
       
   672 		{
       
   673 		// We should add the drive in the drive list.
       
   674 		// Check if the drive list is full
       
   675 		if(iDriveList->Count() < KMaxDriveSupported)
       
   676 			{
       
   677 			// If the drive list is NOT full, insert the new
       
   678 			// current drive entry at the beginning of the list.
       
   679 
       
   680 			TUint KFirstPriority = 1;
       
   681 			AddDriveToListL((TDriveNumber) aDrive, KFirstPriority);
       
   682 			}
       
   683 		else
       
   684 			{
       
   685 			// If the drive list is full, check the last drive
       
   686 			// in the drive list.
       
   687 
       
   688 			// If the last drive is the current drive, remove the
       
   689 			// second last drive from the preferred drive list.
       
   690 			if(iDriveList->CurrentDriveIndex() == KMaxDriveSupported - 1)
       
   691 				{
       
   692 				RemoveDriveFromListL((*iDriveList)[KMaxDriveSupported - 2].driveNum);
       
   693 				}
       
   694 			else
       
   695 				{
       
   696 				// If the last drive is not the current drive, remove
       
   697 				// it from the list. 
       
   698 				RemoveDriveFromListL((*iDriveList)[KMaxDriveSupported - 1].driveNum);
       
   699 				}
       
   700 
       
   701 			// Now insert the new current drive entry at the 
       
   702 			// beginning of the list.
       
   703 			TUint KFirstPriority = 1;
       
   704 			AddDriveToListL((TDriveNumber)aDrive, KFirstPriority);
       
   705 			}
       
   706 		
       
   707 		// Complete the caller.
       
   708 		if(aStatus)
       
   709 			{
       
   710 			User::RequestComplete(aStatus, KErrNone);
       
   711 			}
       
   712 		}
       
   713 	// If the new drive is already present in the preferred drive list.
       
   714 	else
       
   715 		{
       
   716 		// The drive status should be either 
       
   717 		// EMsvMessageStoreAvailable or EMsvMessageStoreUnavailable.
       
   718 		if( (EMsvMessageStoreAvailableStatus   != (*iDriveList)[newCurrentDriveIndex].status) &&
       
   719 			(EMsvMessageStoreUnavailableStatus != (*iDriveList)[newCurrentDriveIndex].status)
       
   720 		  )
       
   721 			{
       
   722 			User::Leave(KErrNotSupported);
       
   723 			}
       
   724 	
       
   725 		// Check if server is busy.
       
   726 		if (0 < OutstandingOperations())
       
   727 			{
       
   728 			User::Leave(KErrServerBusy);
       
   729 			}
       
   730 	
       
   731 		iStartupState = EMsvMediaChanged;
       
   732 		
       
   733 		// Perform Change Drive.
       
   734 		if(aStatus)
       
   735 			{
       
   736 			User::LeaveIfError(iContext->ChangeDrive(newCurrentDriveIndex, *aStatus));
       
   737 			}
       
   738 		else
       
   739 			{
       
   740 			User::LeaveIfError(iContext->ChangeDrive(newCurrentDriveIndex));
       
   741 			}
       
   742 				
       
   743 		// Remove the drive 
       
   744 		TMsvPreferredDrive driveEntry = (*iDriveList)[newCurrentDriveIndex];
       
   745 		iDriveList->Remove(newCurrentDriveIndex);
       
   746 		iDriveList->Insert(driveEntry, 0);
       
   747 		iDriveList->SetCurrentDriveIndex(0);
       
   748 		iIndexDrive = (*iDriveList)[0].driveNum;
       
   749 	
       
   750 		// Update the CenRep with the changes to the preferred drive list.
       
   751 		UpdateRepositoryL();
       
   752 	
       
   753 		// Update the notifier list.
       
   754 		CMsvDiskChangeNotifier* notifier = iNotifier[newCurrentDriveIndex];
       
   755 		iNotifier.Remove(newCurrentDriveIndex);
       
   756 		iNotifier.Insert(notifier, 0);
       
   757 		}
       
   758 	
       
   759 	// Changes for 1667.
       
   760 	if(iSearchSortCacheManager)
       
   761 		{   
       
   762 		iSearchSortCacheManager->ResetSearchSortCache();
       
   763 		}
       
   764 	
       
   765 	iStartupState = EMsvNullNotification;
       
   766 	}
       
   767 
       
   768 
       
   769 
       
   770 
       
   771 // This function is called when ChangeDrive() 
       
   772 // is completed in index context.
       
   773 void CMsvServer::ChangeDriveComplete(TInt aError, TBool aRunMailInit, TDriveNumber aNewDrive)
       
   774 	{
       
   775 #ifndef _NO_SERVER_LOGGING_
       
   776 	Log(_L("ChangeDrive() complete with error %d"), aError);
       
   777 #endif
       
   778 
       
   779 	if (!aError)
       
   780 		{
       
   781 		for(TInt index = 0; index < iNotifier.Count(); ++index)
       
   782 			{
       
   783 			iNotifier[index]->Cancel();
       
   784 			}
       
   785 
       
   786 #ifndef _NO_SERVER_LOGGING_
       
   787 		Log(_L("Deleting iBackup"));
       
   788 #endif
       
   789 
       
   790 		delete iBackup;
       
   791 		iBackup = NULL;
       
   792 		// To Gracefully handle the missing backup server.
       
   793 		TRAP_IGNORE(iBackup = CMsvBackupHandler::NewL(*this));
       
   794 
       
   795 		// Run mailinit.
       
   796 		TUint unused;
       
   797 		iFs.SetSessionToPrivate(aNewDrive);
       
   798 		TBool initNotCompleted = (iFs.Att(KMsvStoreInitFileName, unused)!=KErrNotFound);
       
   799 		if ((initNotCompleted || aRunMailInit) && !(iDebug))
       
   800 			{
       
   801 			RunMailInitExe(aNewDrive);
       
   802 			}
       
   803 
       
   804 		// Send change drive notification.
       
   805 		NotifyChanged(EMsvMediaChanged, KMsvNullIndexEntryId, iIndexDrive, aNewDrive);
       
   806 
       
   807 		// Reset the index error state
       
   808 		iContext->IndexAdapter()->SetErrorState(KErrNone);
       
   809 		iStartupState = EMsvNullNotification;
       
   810 	
       
   811 		// Restart disk change notifications.
       
   812 		for(TInt index = 0; index < iNotifier.Count(); ++index)
       
   813 			{
       
   814 			if(!iNotifier[index]->IsActive())
       
   815 				{
       
   816 				iNotifier[index]->Start();
       
   817 				}
       
   818 			}
       
   819 		}	   // if (!aError)
       
   820 
       
   821 	// Remember the error
       
   822 	iLoadError = aError;
       
   823 	}
       
   824 	
       
   825 	
       
   826 
       
   827 
       
   828 /**
       
   829  * CreatePreferredDriveList()
       
   830  * @param None.
       
   831  * @return None.
       
   832  *
       
   833  * Creates a preferred drive list.
       
   834  * 1. Create an initial preferred drive list.
       
   835  * 2. Check if a CenRep has been created.
       
   836  *  2.1. CenRep has been created. Read from CenRep and fill the initial preferred
       
   837  *	   drive list.
       
   838  *  2.2. CenRep has not been created yet. Check if the config file exists.
       
   839  *	  2.2.1. Config file exists. Fill the initial preferred drive list from it.
       
   840  *	  2.2.2. Save this in the CenRep.
       
   841  */
       
   842 void CMsvServer::CreatePreferredDriveListL()
       
   843 	{
       
   844 	_LIT(KDriveNameFormat, "PriorityDrive%d");
       
   845 	
       
   846 	
       
   847 	// 1. Create an initial preferred drive list.
       
   848 	iDriveList = CMsvPreferredDriveList::CreateL();
       
   849 	
       
   850 	// 2. Check if a CenRep has been created.
       
   851 	// We use CRepository to open the CenRep and read the first key
       
   852 	// from it. The CenRep is valid if the value returned is valid,
       
   853 	// i.e. <= EDriveZ in this case.
       
   854 	CRepository* repository = CRepository::NewL(KUidConfigFile);
       
   855 	CleanupStack::PushL(repository);
       
   856 	TUint keyIndex = 0;
       
   857 	TInt driveIndex = 0;
       
   858 	TInt driveNum;
       
   859 	TInt err = repository->Get(keyIndex, driveNum);
       
   860 		
       
   861 	// 2.1. CenRep has been created. Read from CenRep and fill the initial preferred
       
   862 	//	  drive list.
       
   863 	// <= EDriveZ will be a valid drive number and will mean that CenRep has
       
   864 	// not been initialized by us yet.
       
   865 	if( (err == KErrNone) && (driveNum <= EDriveZ) )
       
   866 		{
       
   867 		for(; keyIndex < KMaxDriveSupported; ++keyIndex)
       
   868 			{
       
   869 			if(keyIndex)
       
   870 				{
       
   871 				User::LeaveIfError(repository->Get(keyIndex, driveNum));
       
   872 				if(driveNum > EDriveZ)
       
   873 					{
       
   874 					break;
       
   875 					}
       
   876 				}
       
   877 						
       
   878 			// Insert this drive in the list at the appropriate index.
       
   879 			TMsvPreferredDrive driveEntry;
       
   880 			driveEntry.driveNum = (TDriveNumber) driveNum;
       
   881 			driveEntry.driveId = KMsvInvalidDriveId;
       
   882 			driveEntry.status = EMsvInvalidDriveStatus;
       
   883 			iDriveList->Insert(driveEntry, driveIndex);
       
   884 			++driveIndex;
       
   885 			}
       
   886 		}
       
   887 	
       
   888 	// 2.2. CenRep has not been created yet. Check if the config file exists.
       
   889 	else
       
   890 		{
       
   891 		CMsvIniData* iniConfigFile = NULL;
       
   892 		
       
   893 		TRAPD(err, iniConfigFile = CMsvIniData::NewL(KPreferredDriveListFilePath));
       
   894 		if(KErrNone == err)
       
   895 			{
       
   896 			CleanupStack::PushL(iniConfigFile);
       
   897 			
       
   898 			// List of drives currently present in the device.
       
   899 			TBool systemDriveAdded = EFalse;
       
   900 			TInt systemDrive = RFs::GetSystemDrive();
       
   901 			TName driveNameMacro;
       
   902 			TDriveList driveList;
       
   903 			User::LeaveIfError(iFs.DriveList(driveList));	   
       
   904 			
       
   905 			// Add entries into preferred drive list.
       
   906 			keyIndex = 0;
       
   907 			driveIndex = 0;
       
   908 			for(TInt index = 1; index <= KMaxDriveSupported; ++index)
       
   909 				{
       
   910 				// Read drive number from ini file.
       
   911 				TInt driveNumber;
       
   912 				TPtrC ptr(NULL, 0);
       
   913 				driveNameMacro.Format(KDriveNameFormat, index);
       
   914 				TBool found = iniConfigFile->FindVar(driveNameMacro, ptr);
       
   915 				if( !found || 
       
   916 					KErrNone != RFs::CharToDrive((TChar)ptr[0], driveNumber)
       
   917 				  )
       
   918 					{		   
       
   919 					continue;
       
   920 					}
       
   921 				
       
   922 				// Check if the drive is present in the device and
       
   923 				// is not a ROM drive.
       
   924 				if( (KDriveAbsent == driveList[driveNumber]) ||
       
   925 					(driveNumber == EDriveZ)
       
   926 				  )
       
   927 					{
       
   928 					continue;
       
   929 					}				   
       
   930 							
       
   931 				// Check for duplicates before adding in the drive list.
       
   932 				TBool entryFound = EFalse;
       
   933 				for(TInt i = 0; i < driveIndex; i++)
       
   934 					{
       
   935 					if((*iDriveList)[i].driveNum == driveNumber)
       
   936 						{
       
   937 						entryFound = ETrue;
       
   938 						break;
       
   939 						}
       
   940 					}
       
   941 				
       
   942 				if(entryFound)
       
   943 					{
       
   944 					continue;
       
   945 					}
       
   946 
       
   947 				// If it is a system drive...
       
   948 				if(driveNumber == systemDrive)
       
   949 					{
       
   950 					systemDriveAdded = ETrue;
       
   951 					}
       
   952 						
       
   953 				// Add drive entry into preferred drive list.
       
   954 				TMsvPreferredDrive driveEntry;
       
   955 				driveEntry.driveNum = (TDriveNumber) driveNumber;
       
   956 				driveEntry.driveId = KMsvInvalidDriveId;
       
   957 				driveEntry.status = EMsvInvalidDriveStatus;
       
   958 				iDriveList->Insert(driveEntry, driveIndex);
       
   959 				User::LeaveIfError(repository->Set(keyIndex, (TInt)((*iDriveList)[driveIndex].driveNum)));
       
   960 				++driveIndex;
       
   961 				++keyIndex;
       
   962 				} //for(TInt index = 1; index <= KMaxDriveSupported; ++index)
       
   963 				
       
   964 			CleanupStack::PopAndDestroy();  // iniConfigFile
       
   965 			
       
   966 			// If the system drive is not already added.
       
   967 			if(!systemDriveAdded)
       
   968 				{
       
   969 				// If the number of drives in the drive list is already 7,
       
   970 				// Replace the last drive with the system drive.
       
   971 				TInt index = (driveIndex < KMaxDriveSupported)? driveIndex: 6;
       
   972 				
       
   973 				TMsvPreferredDrive driveEntry;
       
   974 				driveEntry.driveNum = (TDriveNumber) systemDrive;
       
   975 				driveEntry.driveId = KMsvInvalidDriveId;
       
   976 				driveEntry.status = EMsvInvalidDriveStatus;
       
   977 				iDriveList->Insert(driveEntry, index);
       
   978 				User::LeaveIfError(repository->Set(keyIndex, (TInt)((*iDriveList)[index].driveNum)));
       
   979 				}
       
   980 			}
       
   981 		
       
   982 		// Prefered drive list config file is not available. Add system drive to the drive list.
       
   983 		else
       
   984 			{
       
   985 			TMsvPreferredDrive driveEntry;
       
   986 			driveEntry.driveNum = RFs::GetSystemDrive();
       
   987 			driveEntry.driveId = KMsvInvalidDriveId;
       
   988 			driveEntry.status = EMsvInvalidDriveStatus;
       
   989 			iDriveList->Insert(driveEntry, 0);
       
   990 			keyIndex = 0;
       
   991 			User::LeaveIfError(repository->Set(keyIndex, (TInt)((*iDriveList)[0].driveNum)));
       
   992 			}
       
   993 		}
       
   994 
       
   995 	CleanupStack::PopAndDestroy(); //repository
       
   996 	}
       
   997 
       
   998 
       
   999 
       
  1000 /**
       
  1001  * PrepareDriveForDeletionL()
       
  1002  * @param TDriveNumber: Drive number under consideration.
       
  1003  *
       
  1004  */
       
  1005 void CMsvServer::PrepareDriveForDeletionL(TDriveNumber aDrive)
       
  1006 	{
       
  1007 	// Drive should be present in the preferred drive list.
       
  1008 	TInt index = 0;
       
  1009 	TBool isDriveFound = EFalse;
       
  1010 	for(; index < iDriveList->Count(); index++)
       
  1011 		{
       
  1012 		if(aDrive == (*iDriveList)[index].driveNum)
       
  1013 			{
       
  1014 			isDriveFound = ETrue;
       
  1015 			break;
       
  1016 			}
       
  1017 		}
       
  1018 	if(!isDriveFound)
       
  1019 		{
       
  1020 		return;
       
  1021 		}
       
  1022 		
       
  1023 	// Following operations needs to be performed
       
  1024 	// only if the message store exists in the drive.
       
  1025 	if(EMsvMessageStoreAvailableStatus == (*iDriveList)[index].status)
       
  1026 		{
       
  1027 		// Cleanup cache and detach the corresponding DB.
       
  1028 		IndexAdapter().RemoveDriveL((*iDriveList)[index].driveId, index, EFalse);
       
  1029 		
       
  1030 		// Send notification to all registered clients to refresh their view of messaging.
       
  1031 		NotifyChanged(EMsvRefreshMessageView, KMsvNullIndexEntryId, (*iDriveList)[index].driveNum);	 
       
  1032 		}
       
  1033 	}
       
  1034 	
       
  1035 		
       
  1036 	
       
  1037 
       
  1038 /**
       
  1039  * RemoveDriveFromListL()
       
  1040  * @param TDriveNumber: Drive number of the drive to be removed.
       
  1041  * 
       
  1042  */
       
  1043 void CMsvServer::RemoveDriveFromListL(TDriveNumber aDriveNumber)
       
  1044 	{
       
  1045 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1046 	iNotification = EMsvNullNotification;
       
  1047 #endif
       
  1048 
       
  1049 	// System drive cannot be removed from the preferred
       
  1050 	// drive list.
       
  1051 	if(aDriveNumber == RFs::GetSystemDrive())
       
  1052 		{
       
  1053 		User::Leave(KErrArgument);
       
  1054 		}
       
  1055 	
       
  1056 	// Drive should be present in the preferred drive list.
       
  1057 	TInt index = 0;
       
  1058 	TBool isDriveFound = EFalse;
       
  1059 	for(; index < iDriveList->Count(); index++)
       
  1060 		{
       
  1061 		if(aDriveNumber == (*iDriveList)[index].driveNum)
       
  1062 			{
       
  1063 			isDriveFound = ETrue;
       
  1064 			break;
       
  1065 			}
       
  1066 		}
       
  1067 		
       
  1068 	if(!isDriveFound)
       
  1069 		{
       
  1070 		User::Leave(KErrNotFound);
       
  1071 		}
       
  1072 		
       
  1073 	// This is a request to remove current drive.
       
  1074 	TUint curDriveIndex = iDriveList->CurrentDriveIndex();
       
  1075 	if(curDriveIndex == index)
       
  1076 		{
       
  1077 		// Make sure there are no pending operations
       
  1078 		// with the server.
       
  1079 		if (0 < OutstandingOperations())
       
  1080 			{
       
  1081 			User::Leave(KErrServerBusy);
       
  1082 			}
       
  1083 			
       
  1084 		iStartupState = EMsvMediaChanged;
       
  1085 		
       
  1086 		// Check for the next available drive.
       
  1087 		// This assumes that there is always a drive available.
       
  1088 		TInt newDriveIndex = index + 1;
       
  1089 		for(; newDriveIndex < iDriveList->Count(); newDriveIndex++)
       
  1090 			{
       
  1091 			if( (EMsvMessageStoreAvailableStatus   == (*iDriveList)[newDriveIndex].status) ||
       
  1092 				(EMsvMessageStoreUnavailableStatus == (*iDriveList)[newDriveIndex].status)
       
  1093 			  )
       
  1094 				{
       
  1095 				break;
       
  1096 				}
       
  1097 			}
       
  1098 		
       
  1099 		// Perform ChangeDrive() operation.
       
  1100 		User::LeaveIfError(iContext->ChangeDrive(newDriveIndex, EFalse));
       
  1101 		
       
  1102 		// Update the current drive index.
       
  1103 		iDriveList->SetCurrentDriveIndex(newDriveIndex);
       
  1104 		
       
  1105 		iIndexDrive = (*iDriveList)[newDriveIndex].driveNum;
       
  1106 		iStartupState = EMsvNullNotification;
       
  1107 		
       
  1108 		// Remove drive entry from the preferred drive list.
       
  1109 		iDriveList->Remove(index);  
       
  1110 		}
       
  1111 	else
       
  1112 		// This handles removal of non-current drive.
       
  1113 		{
       
  1114 		// Following operations needs to be performed
       
  1115 		// only if the message store exists in the drive.
       
  1116 		if(EMsvMessageStoreAvailableStatus == (*iDriveList)[index].status)
       
  1117 			{
       
  1118 			// Cleanup cache and detach the corresponding DB.
       
  1119 			IndexAdapter().RemoveDriveL((*iDriveList)[index].driveId, index, EFalse);
       
  1120 				
       
  1121 			// Send notification to all registered clients to refresh their view of messaging.
       
  1122 			NotifyChanged(EMsvRefreshMessageView, KMsvNullIndexEntryId, (*iDriveList)[index].driveNum);
       
  1123 			}
       
  1124 		
       
  1125 		// Remove drive entry from the preferred drive list.
       
  1126 		iDriveList->Remove(index);
       
  1127 		}
       
  1128 		
       
  1129 	// Update the CenRep with the changes to the preferred drive list.
       
  1130 	UpdateRepositoryL();
       
  1131 	
       
  1132 	// Remove the notifier for this drive.
       
  1133 	delete iNotifier[index];
       
  1134 	iNotifier.Remove(index);	
       
  1135 	}
       
  1136 	
       
  1137 	
       
  1138 
       
  1139 
       
  1140 /**
       
  1141  * AddDriveToListL()
       
  1142  * @param TDriveNumber: Drive number of the drive to be added.
       
  1143  * @param CMsvServerSession*: The calling session.
       
  1144  * @param TUint: Priority of the new drive.
       
  1145  * 
       
  1146  */ 
       
  1147 void CMsvServer::AddDriveToListL(TDriveNumber aDriveNumber, TUint& aPriority, CMsvServerSession* aCurrentSession /*DEFAULT=NULL*/)
       
  1148 	{
       
  1149 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1150 	iNotification = EMsvNullNotification;
       
  1151 #endif
       
  1152 
       
  1153 	TInt driveIndex = aPriority - 1;
       
  1154 	// Check if the limit of allowable drives has been reached.
       
  1155 	if(KMaxDriveSupported == iDriveList->Count())
       
  1156 		{
       
  1157 		User::Leave(KErrNotSupported);
       
  1158 		}
       
  1159 			
       
  1160 	// Check if the drive is present in the device.
       
  1161 	TDriveList driveList;
       
  1162 	User::LeaveIfError(iFs.DriveList(driveList));
       
  1163 	if (0 == driveList[aDriveNumber])
       
  1164 		{
       
  1165 		User::Leave(KErrNotFound);
       
  1166 		}
       
  1167 
       
  1168 	// Check if the priority is valid.
       
  1169 	if( (0 > driveIndex) || (KMaxDriveSupported - 1 < driveIndex) )
       
  1170 		{
       
  1171 		User::Leave(KErrArgument);
       
  1172 		}
       
  1173 	
       
  1174 	// Check if the drive already present in the preferred drive list.
       
  1175 	TInt index = 0;
       
  1176 	for(; index < iDriveList->Count(); index++)
       
  1177 		{
       
  1178 		if(aDriveNumber == (*iDriveList)[index].driveNum)
       
  1179 			{
       
  1180 			User::Leave(KErrAlreadyExists);
       
  1181 			break;
       
  1182 			}
       
  1183 		}
       
  1184 		
       
  1185 	// Create the drive object.
       
  1186 	TMsvPreferredDrive driveEntry;
       
  1187 	driveEntry.driveNum = aDriveNumber;
       
  1188 	driveEntry.driveId = KMsvInvalidDriveId;
       
  1189 	driveEntry.status = EMsvInvalidDriveStatus;
       
  1190 	
       
  1191 	// This is to avoid USER:131 panic.
       
  1192 	if(driveIndex > iDriveList->Count())
       
  1193 		{
       
  1194 		driveIndex = iDriveList->Count();
       
  1195 		aPriority = driveIndex + 1;
       
  1196 		}
       
  1197 	// Create the drive entry in preferred drive list.
       
  1198 	iDriveList->Insert(driveEntry, driveIndex);
       
  1199 		
       
  1200 	// Update the new drive status.
       
  1201 	TDriveState statusDuringUpdate = EMsvInvalidDriveStatus;
       
  1202 	TRAPD(err, iContext->UpdateDriveStatusL(driveIndex, statusDuringUpdate));
       
  1203 
       
  1204 	// Undo the insertion if there is an error.
       
  1205 	if(KErrNone != err)
       
  1206 		{
       
  1207 		iDriveList->Remove(driveIndex);
       
  1208 		User::Leave(err);
       
  1209 		}
       
  1210 			
       
  1211 	// Send a message store corrupt notification first if it was wiped. This needs to be
       
  1212 	// sent before the drive change notification. Other notifications are sent below.
       
  1213 	if(EMsvMessageStoreCorruptStatus == statusDuringUpdate)
       
  1214 		{
       
  1215 		TMsvPackedChangeNotification package(iChange);
       
  1216 		package.Pack(EMsvMessageStoreCorrupt, KMsvNullIndexEntryId, driveEntry.driveNum, 0);
       
  1217 		if(aCurrentSession)
       
  1218 			{
       
  1219 			TRAP_IGNORE(aCurrentSession->NotifyChangedL(iChange, EFalse));
       
  1220 			}
       
  1221 		}
       
  1222 
       
  1223 	TDriveState driveStatus = (*iDriveList)[driveIndex].status;
       
  1224 	// If the priority of the new drive is higher than the 
       
  1225 	// current drive, we need to change the current drive.
       
  1226 	TUint curDriveIndex = iDriveList->CurrentDriveIndex();
       
  1227 	if(driveIndex <= curDriveIndex)
       
  1228 		{
       
  1229 		// Change the drive only if a valid message store
       
  1230 		// exists or can be created.
       
  1231 		if( (KErrNone == err) &&
       
  1232 			( (EMsvMessageStoreAvailableStatus   == driveStatus) ||
       
  1233 			  (EMsvMessageStoreUnavailableStatus == driveStatus)
       
  1234 			)
       
  1235 		  )		
       
  1236 			{
       
  1237 			// Make sure there are no pending operations
       
  1238 			// with the server.
       
  1239 			if (0 < OutstandingOperations())
       
  1240 				{
       
  1241 				iDriveList->Remove(driveIndex);
       
  1242 				User::Leave(KErrServerBusy);
       
  1243 				}
       
  1244 				
       
  1245 			TBool isEntryRemovalRequired = EFalse;
       
  1246 			if(EMsvMessageStoreAvailableStatus == (*iDriveList)[driveIndex].status)
       
  1247 				{
       
  1248 				isEntryRemovalRequired = ETrue;
       
  1249 				}
       
  1250 				
       
  1251 			iStartupState = EMsvMediaChanged;
       
  1252 			err = iContext->ChangeDrive(driveIndex, ETrue);
       
  1253 			if(KErrNone == err)
       
  1254 				{
       
  1255 				TUint oldDriveNum = iDriveList->CurrentDriveNumber();
       
  1256 				iDriveList->SetCurrentDriveIndex(driveIndex);
       
  1257 				iIndexDrive = (*iDriveList)[driveIndex].driveNum;
       
  1258 				
       
  1259 				// Remove incomplete entries from the new drive.
       
  1260 				if(isEntryRemovalRequired)
       
  1261 					{
       
  1262 					iContext->GetInPreparationIds((*iDriveList)[driveIndex].driveId);		   
       
  1263 					if (iContext->Remove().Count())
       
  1264 						{
       
  1265 						RemoveEntry(KMsvNullIndexEntryId);
       
  1266 						}
       
  1267 					}
       
  1268 				}
       
  1269 			iStartupState = EMsvNullNotification;
       
  1270 			}
       
  1271 		
       
  1272 		// Undo the insertion if there is an error.
       
  1273 		if(KErrNone != err)
       
  1274 			{
       
  1275 			iDriveList->Remove(driveIndex);
       
  1276 			User::Leave(err);
       
  1277 			}
       
  1278 		}
       
  1279 	else
       
  1280 		// Priority is lower than the current drive.
       
  1281 		{
       
  1282 		// Update index cache and the database, only if
       
  1283 		// message store is available in the new drive.
       
  1284 
       
  1285 		if(EMsvMessageStoreAvailableStatus == driveStatus)
       
  1286 			{
       
  1287 			TRAP(err, IndexAdapter().AddDriveL(driveIndex));
       
  1288 			if(KErrNone == err)
       
  1289 				{
       
  1290 				iContext->GetInPreparationIds((*iDriveList)[driveIndex].driveId);		   
       
  1291 				if (iContext->Remove().Count())
       
  1292 					{
       
  1293 					RemoveEntry(KMsvNullIndexEntryId);
       
  1294 					}
       
  1295 				
       
  1296 				// Send notification to all registered clients to refresh their view of messaging.
       
  1297 				NotifyChanged(EMsvRefreshMessageView, KMsvNullIndexEntryId, (*iDriveList)[driveIndex].driveNum);
       
  1298 				}
       
  1299 			else
       
  1300 				{
       
  1301 				iDriveList->Remove(driveIndex);
       
  1302 				User::Leave(err);
       
  1303 				}
       
  1304 			}
       
  1305 		}
       
  1306 	
       
  1307 	// Update the CenRep with the changes to the preferred drive list.
       
  1308 	UpdateRepositoryL();
       
  1309 	
       
  1310 	// Add a notifier for this drive.
       
  1311 	TDriveUnit driveValue = TDriveUnit(aDriveNumber);
       
  1312 	CMsvDiskChangeNotifier* diskChangeNotifier = CMsvDiskChangeNotifier::NewL(driveValue, *this);
       
  1313 	CleanupStack::PushL(diskChangeNotifier);
       
  1314 	User::LeaveIfError(iNotifier.Insert(diskChangeNotifier, driveIndex));
       
  1315 	diskChangeNotifier->Start();
       
  1316 	CleanupStack::Pop();
       
  1317 	
       
  1318 	// Send a notification to only current client if and as set above.
       
  1319 	if(aCurrentSession)
       
  1320 		{
       
  1321 		TMsvPackedChangeNotification package(iChange);
       
  1322 		switch(statusDuringUpdate)
       
  1323 			{
       
  1324 			case EMsvDriveDiskNotAvailableStatus:
       
  1325 				package.Pack(EMsvDiskNotAvailable, KMsvNullIndexEntryId, driveEntry.driveNum, 0);
       
  1326 				TRAP_IGNORE(aCurrentSession->NotifyChangedL(iChange, EFalse));
       
  1327 				break;
       
  1328 			
       
  1329 			case EMsvMessageStoreNotSupportedStatus:
       
  1330 				package.Pack(EMsvMessageStoreNotSupported, KMsvNullIndexEntryId, driveEntry.driveNum, 0);
       
  1331 				TRAP_IGNORE(aCurrentSession->NotifyChangedL(iChange, EFalse));
       
  1332 				break;
       
  1333 				
       
  1334 			default:
       
  1335 				break;
       
  1336 			}
       
  1337 		}
       
  1338 	}
       
  1339 	
       
  1340 	
       
  1341 
       
  1342 
       
  1343 /**
       
  1344  * UpdateDrivePriorityL()
       
  1345  * @param TDriveNumber: Drive number of the drive to be updated.
       
  1346  * @param TUint: New priority of the drive.
       
  1347  * 
       
  1348  */ 
       
  1349 void CMsvServer::UpdateDrivePriorityL(TDriveNumber aDriveNumber, TUint& aNewPriority)
       
  1350 	{
       
  1351 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1352 	iNotification = EMsvNullNotification;
       
  1353 #endif
       
  1354 
       
  1355 	TInt updatedDriveIndex = aNewPriority - 1;
       
  1356 
       
  1357 	// Check if the new priority is valid.
       
  1358 	if( (0 > updatedDriveIndex) || (6 < updatedDriveIndex) )
       
  1359 		{
       
  1360 		User::Leave(KErrArgument);
       
  1361 		}
       
  1362 
       
  1363 
       
  1364 	// Drive should be present in the preferred drive list.
       
  1365 	TInt index = 0;
       
  1366 	TBool isDriveFound = EFalse;
       
  1367 	for(; index<CMsvPreferredDriveList::GetDriveList()->Count(); index++)
       
  1368 		{
       
  1369 		if(aDriveNumber == (*iDriveList)[index].driveNum)
       
  1370 			{
       
  1371 			isDriveFound = ETrue;
       
  1372 			break;
       
  1373 			}
       
  1374 		}
       
  1375 		
       
  1376 	if(!isDriveFound)
       
  1377 		{
       
  1378 		User::Leave(KErrNotFound);
       
  1379 		}
       
  1380 		
       
  1381 	// If new priority is same as old.
       
  1382 	if(index == updatedDriveIndex)
       
  1383 		{
       
  1384 		return;
       
  1385 		}
       
  1386 
       
  1387 	// Creating a copy of the drive entry.
       
  1388 	TMsvPreferredDrive driveEntry;
       
  1389 	driveEntry.driveNum = (*iDriveList)[index].driveNum;
       
  1390 	driveEntry.driveId = (*iDriveList)[index].driveId;
       
  1391 	driveEntry.status = (*iDriveList)[index].status;
       
  1392 	
       
  1393 	CMsvDiskChangeNotifier* notifier = NULL;
       
  1394 			
       
  1395 	// Check if the current drive priority needs to be updated.
       
  1396 	TUint curDriveIndex = iDriveList->CurrentDriveIndex();
       
  1397 	if(index == curDriveIndex)
       
  1398 		{
       
  1399 		// If the current drive remains current even after updation.
       
  1400 		if(updatedDriveIndex < curDriveIndex)
       
  1401 			{
       
  1402 			iDriveList->Remove(index);
       
  1403 			iDriveList->Insert(driveEntry, updatedDriveIndex);
       
  1404 			iDriveList->SetCurrentDriveIndex(updatedDriveIndex);
       
  1405 			
       
  1406 			// Update the CenRep with the changes to the preferred drive list.
       
  1407 			UpdateRepositoryL();
       
  1408 			
       
  1409 			// Update the notifier list.
       
  1410 			notifier = iNotifier[index];
       
  1411 			iNotifier.Remove(index);
       
  1412 			iNotifier.Insert(notifier, updatedDriveIndex);
       
  1413 			
       
  1414 			return;
       
  1415 			}
       
  1416 		
       
  1417 		// Ignoring the possibility that newDriveIndex 
       
  1418 		// is same as current drive priority.
       
  1419 		
       
  1420 		// Look for new current drive.
       
  1421 		if(updatedDriveIndex > curDriveIndex)
       
  1422 			{
       
  1423 			// Update the priority to avoid USER:131 panic.
       
  1424 			if(updatedDriveIndex >= CMsvPreferredDriveList::GetDriveList()->Count())
       
  1425 				{
       
  1426 				updatedDriveIndex = CMsvPreferredDriveList::GetDriveList()->Count() - 1;
       
  1427 				aNewPriority = updatedDriveIndex + 1;
       
  1428 				}
       
  1429 			
       
  1430 			// Add the current drive in its position.
       
  1431 			// Now current drive is present twice in the drive list.
       
  1432 			// And their drive index are: index and (updatedDriveIndex + 1).
       
  1433 			iDriveList->Insert(driveEntry, updatedDriveIndex + 1);
       
  1434 			TInt newCurrentIndex = curDriveIndex + 1;
       
  1435 			for(; newCurrentIndex<=(updatedDriveIndex+1); newCurrentIndex++)
       
  1436 				{
       
  1437 				if( (EMsvMessageStoreAvailableStatus   == (*iDriveList)[newCurrentIndex].status) ||
       
  1438 					(EMsvMessageStoreUnavailableStatus == (*iDriveList)[newCurrentIndex].status)
       
  1439 				  )
       
  1440 					{
       
  1441 					break;
       
  1442 					}
       
  1443 				}
       
  1444 			
       
  1445 			// If there is no change in the current drive.
       
  1446 			if(newCurrentIndex == updatedDriveIndex + 1)
       
  1447 				{
       
  1448 				iDriveList->Remove(index);
       
  1449 				iDriveList->SetCurrentDriveIndex(updatedDriveIndex);
       
  1450 				
       
  1451 				// Update the CenRep with the changes to the preferred drive list.
       
  1452 				UpdateRepositoryL();
       
  1453 				
       
  1454 				// Update the notifier list.
       
  1455 				notifier = iNotifier[index];
       
  1456 				iNotifier.Remove(index);
       
  1457 				iNotifier.Insert(notifier, updatedDriveIndex);
       
  1458 				
       
  1459 				return;
       
  1460 				}
       
  1461 			else
       
  1462 				{
       
  1463 				// newCurrentIndex is the position of new current drive.
       
  1464 				if (0 < OutstandingOperations())
       
  1465 					{
       
  1466 					User::Leave(KErrServerBusy);
       
  1467 					}
       
  1468 
       
  1469 				iStartupState = EMsvMediaChanged;
       
  1470 									
       
  1471 				// Perform Change Drive.
       
  1472 				User::LeaveIfError(iContext->ChangeDrive(newCurrentIndex, ETrue));
       
  1473 			
       
  1474 				// The drive-id of the old current drive is updated.
       
  1475 				// This should be refelected in the duplicate driveEntry 
       
  1476 				// created in the preferred drive list.
       
  1477 				(*iDriveList)[updatedDriveIndex + 1].driveId = (*iDriveList)[curDriveIndex].driveId;
       
  1478 				// Remove the drive 
       
  1479 				iDriveList->Remove(curDriveIndex);
       
  1480 				iDriveList->SetCurrentDriveIndex(newCurrentIndex - 1);
       
  1481 				
       
  1482 				iIndexDrive = (*iDriveList)[newCurrentIndex - 1].driveNum;
       
  1483 				
       
  1484 				// Update the CenRep with the changes to the preferred drive list.
       
  1485 				UpdateRepositoryL();
       
  1486 				
       
  1487 				// Update the notifier list.
       
  1488 				notifier = iNotifier[index];
       
  1489 				iNotifier.Remove(index);
       
  1490 				iNotifier.Insert(notifier, updatedDriveIndex);
       
  1491 
       
  1492 				iStartupState = EMsvNullNotification;
       
  1493 				return;
       
  1494 				}		   
       
  1495 			}
       
  1496 		}
       
  1497 	else
       
  1498 		{
       
  1499 		// Updating non-current drive.
       
  1500 		
       
  1501 		// The drive can be the new current drive.
       
  1502 		if(updatedDriveIndex <= curDriveIndex)
       
  1503 			{
       
  1504 			// Check if the drive can be made the current drive.
       
  1505 			if( (EMsvMessageStoreAvailableStatus   == (*iDriveList)[index].status) ||
       
  1506 				(EMsvMessageStoreUnavailableStatus == (*iDriveList)[index].status)
       
  1507 			  )
       
  1508 				{
       
  1509 				// updatedDriveIndex is the position of new current drive.
       
  1510 				if (0 < OutstandingOperations())
       
  1511 					{
       
  1512 					User::Leave(KErrServerBusy);
       
  1513 					}
       
  1514 				iStartupState = EMsvMediaChanged;
       
  1515 				
       
  1516 				// Perform Change Drive.
       
  1517 				User::LeaveIfError(iContext->ChangeDrive(index, ETrue));
       
  1518 			
       
  1519 				// Remove the drive 
       
  1520 				driveEntry = (*iDriveList)[index];
       
  1521 				iDriveList->Remove(index);
       
  1522 				iDriveList->Insert(driveEntry, updatedDriveIndex);
       
  1523 				iDriveList->SetCurrentDriveIndex(updatedDriveIndex);
       
  1524 								
       
  1525 				iIndexDrive = (*iDriveList)[updatedDriveIndex].driveNum;
       
  1526 				
       
  1527 				// Update the CenRep with the changes to the preferred drive list.
       
  1528 				UpdateRepositoryL();
       
  1529 				
       
  1530 				// Update the notifier list.
       
  1531 				notifier = iNotifier[index];
       
  1532 				iNotifier.Remove(index);
       
  1533 				iNotifier.Insert(notifier, updatedDriveIndex);
       
  1534 				
       
  1535 				iStartupState = EMsvNullNotification;
       
  1536 				return;			 
       
  1537 				}
       
  1538 			else
       
  1539 				{
       
  1540 				// A message store cannot be created in the drive.
       
  1541 				// Hence no change in the current drive.
       
  1542 				
       
  1543 				// Remove the drive 
       
  1544 				iDriveList->Remove(index);
       
  1545 				iDriveList->Insert(driveEntry, updatedDriveIndex);
       
  1546 
       
  1547 				// Update the CenRep with the changes to the preferred drive list.
       
  1548 				UpdateRepositoryL();
       
  1549 				
       
  1550 				// Update the notifier list.
       
  1551 				notifier = iNotifier[index];
       
  1552 				iNotifier.Remove(index);
       
  1553 				iNotifier.Insert(notifier, updatedDriveIndex);
       
  1554 
       
  1555 				return; 
       
  1556 				}		   
       
  1557 			}	   
       
  1558 		else
       
  1559 			{
       
  1560 			iDriveList->Remove(index);
       
  1561 			
       
  1562 			if(updatedDriveIndex >= CMsvPreferredDriveList::GetDriveList()->Count())
       
  1563 				{
       
  1564 				updatedDriveIndex = CMsvPreferredDriveList::GetDriveList()->Count();
       
  1565 				aNewPriority = updatedDriveIndex + 1;
       
  1566 				}	   
       
  1567 			iDriveList->Insert(driveEntry, updatedDriveIndex);
       
  1568 
       
  1569 			// Update the CenRep with the changes to the preferred drive list.
       
  1570 			UpdateRepositoryL();
       
  1571 			
       
  1572 			// Update the notifier list.
       
  1573 			notifier = iNotifier[index];
       
  1574 			iNotifier.Remove(index);
       
  1575 			iNotifier.Insert(notifier, updatedDriveIndex);
       
  1576 			
       
  1577 			return;
       
  1578 			}
       
  1579 		}   
       
  1580 	}
       
  1581 
       
  1582 
       
  1583 
       
  1584 
       
  1585 /**
       
  1586  * UpdateRepositoryL()
       
  1587  * @param None.
       
  1588  * @return None.
       
  1589  * 
       
  1590  * Updates CenRep with changes to the preferred drive list.
       
  1591  */
       
  1592 void CMsvServer::UpdateRepositoryL()
       
  1593 	{
       
  1594 	CRepository* repository = CRepository::NewL(KUidConfigFile);
       
  1595 	CleanupStack::PushL(repository);
       
  1596 	
       
  1597 	// Reset everything in the repository. New drive list information
       
  1598 	// will be written.
       
  1599 	repository->Reset();
       
  1600 	
       
  1601 	TInt driveIndex = 0;	
       
  1602 	for(TUint keyIndex=0; keyIndex < CMsvPreferredDriveList::GetDriveList()->Count(); ++keyIndex, ++driveIndex)
       
  1603 		{
       
  1604 		User::LeaveIfError(repository->Set(keyIndex, (*iDriveList)[driveIndex].driveNum));
       
  1605 		}
       
  1606 		
       
  1607 	// Setting up the current drive information.
       
  1608 	User::LeaveIfError(repository->Set(KCenRepCurrentDriveKey, CMsvPreferredDriveList::GetDriveList()->CurrentDriveNumber()));
       
  1609 	CleanupStack::PopAndDestroy(); //repository
       
  1610 	}
       
  1611 	
       
  1612 
       
  1613 
       
  1614 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1615 void CMsvServer::DiskRemoved(const TDriveUnit& aDrive, TBool aTestRemoval/*DEFAULT = EFalse*/)
       
  1616 #else
       
  1617 void CMsvServer::DiskRemoved(const TDriveUnit& aDrive)
       
  1618 #endif
       
  1619 	{
       
  1620 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1621 	TRAPD(err, DoDiskRemovedL(aDrive, aTestRemoval));
       
  1622 #else
       
  1623 	TRAPD(err, DoDiskRemovedL(aDrive));
       
  1624 #endif
       
  1625 	
       
  1626 	TRAP_IGNORE(UpdateRepositoryL());
       
  1627 	if(KErrNone != err)
       
  1628 		{
       
  1629 		NotifyChanged(EMsvUnableToProcessDiskNotification, KMsvNullIndexEntryId, TInt(aDrive), 0);	  
       
  1630 		}
       
  1631 	}
       
  1632 
       
  1633 
       
  1634 
       
  1635 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1636 void CMsvServer::DoDiskRemovedL(const TDriveUnit& aDrive, TBool aTestRemoval)
       
  1637 #else
       
  1638 void CMsvServer::DoDiskRemovedL(const TDriveUnit& aDrive)
       
  1639 #endif
       
  1640 	{
       
  1641 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1642 	iNotification = EMsvNullNotification;
       
  1643 #endif
       
  1644 
       
  1645 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  1646 
       
  1647 #ifndef _NO_SERVER_LOGGING_
       
  1648 	Log(_L("Disk %d removed"), TInt(aDrive));
       
  1649 #endif
       
  1650 
       
  1651 	//Find the index of the drive that has been removed.
       
  1652 	TInt driveCount = CMsvPreferredDriveList::GetDriveList()->Count();
       
  1653 	TInt index = 0;
       
  1654 	for(index=0; index < driveCount; ++index)
       
  1655 		{
       
  1656 		if((TInt)(*iDriveList)[index].driveNum == (TInt)aDrive)
       
  1657 			{
       
  1658 			break;
       
  1659 			}
       
  1660 		}
       
  1661 	
       
  1662 	//Record previous drive status before we attempt to update drive's status.
       
  1663 	TDriveState previousDriveStatus = (*iDriveList)[index].status;
       
  1664 	
       
  1665 	//Update the drive's status.
       
  1666 	TDriveState statusDuringUpdate = EMsvInvalidDriveStatus;
       
  1667 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1668 	if(aTestRemoval)
       
  1669 		(*iDriveList)[index].status = EMsvDriveDiskNotAvailableStatus;
       
  1670 	else
       
  1671 #endif
       
  1672 		iContext->UpdateDriveStatusL(index, statusDuringUpdate);
       
  1673 		
       
  1674 	//Check if the disk had a message store in the first place.
       
  1675 	//If yes, then perform removal operations.
       
  1676 	//Note that we do not send a notification for a disk which did
       
  1677 	//not have a message store available.
       
  1678 	if(EMsvMessageStoreAvailableStatus == previousDriveStatus)
       
  1679 		{
       
  1680 		//Check if the disk was removed from the current drive.
       
  1681 		//If yes, then we need to change the drive to the next drive in
       
  1682 		//the list.
       
  1683 		TUint curDriveIndex = iDriveList->CurrentDriveIndex();
       
  1684 		if(index == curDriveIndex)
       
  1685 			{
       
  1686 			//Find the next drive index to change the drive to.
       
  1687 			TInt nextDriveIndex = curDriveIndex + 1;
       
  1688 			for(; nextDriveIndex < driveCount; ++nextDriveIndex)
       
  1689 				{
       
  1690 				if(EMsvMessageStoreAvailableStatus == (*iDriveList)[nextDriveIndex].status ||
       
  1691 				   EMsvMessageStoreUnavailableStatus == (*iDriveList)[nextDriveIndex].status )
       
  1692 					{
       
  1693 					break;
       
  1694 					}
       
  1695 				}
       
  1696 			
       
  1697 			iStartupState = EMsvMediaUnavailable;
       
  1698 
       
  1699 			
       
  1700 			//Change the drive to the above drive and set current drive index.
       
  1701 			User::LeaveIfError(iContext->ChangeDrive(nextDriveIndex, EFalse));
       
  1702 			iDriveList->SetCurrentDriveIndex(nextDriveIndex);
       
  1703 			
       
  1704 			iStartupState = EMsvMediaChanged;
       
  1705 			iIndexDrive = (*iDriveList)[nextDriveIndex].driveNum;
       
  1706 			}
       
  1707 		//If not, we only need to remove the drive from the list.
       
  1708 		else
       
  1709 			{
       
  1710 			iContext->IndexAdapter()->RemoveDriveL((*iDriveList)[index].driveId, index, EFalse);
       
  1711 			
       
  1712 			iStartupState = EMsvNullNotification;
       
  1713 			
       
  1714 			//Send the notification to all registered clients that they need to 
       
  1715 			//refresh their view of messaging.
       
  1716 			NotifyChanged(EMsvRefreshMessageView, KMsvNullIndexEntryId, TInt(aDrive));
       
  1717 			} //if(index == iCurrentDriveIndex)
       
  1718 		} //if(EMsvMessageStoreAvailable == previousDriveStatus)
       
  1719 	
       
  1720 	iStartupState = EMsvNullNotification;
       
  1721 	iContext->IndexAdapter()->SetErrorState(KErrNone);
       
  1722 	}
       
  1723 
       
  1724 
       
  1725 
       
  1726 
       
  1727 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1728 void CMsvServer::DiskInserted(const TDriveUnit& aDrive, TBool aTestInsert/*DEFAULT = EFalse*/)
       
  1729 #else
       
  1730 void CMsvServer::DiskInserted(const TDriveUnit& aDrive)
       
  1731 #endif
       
  1732 	{
       
  1733 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1734 	TRAPD(err, DoDiskInsertedL(aDrive, aTestInsert));
       
  1735 #else
       
  1736 	TRAPD(err, DoDiskInsertedL(aDrive));
       
  1737 #endif
       
  1738 	
       
  1739 	TRAP_IGNORE(UpdateRepositoryL());
       
  1740 	if(KErrNone != err)
       
  1741 		{
       
  1742 		NotifyChanged(EMsvUnableToProcessDiskNotification, KMsvNullIndexEntryId, TInt(aDrive), 0);	  
       
  1743 		}
       
  1744 	}
       
  1745 
       
  1746 
       
  1747 
       
  1748 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1749 void CMsvServer::DoDiskInsertedL(const TDriveUnit& aDrive, TBool aTestInsert)
       
  1750 #else
       
  1751 void CMsvServer::DoDiskInsertedL(const TDriveUnit& aDrive)
       
  1752 #endif
       
  1753 //
       
  1754 // Disk reinserted - Message store available again
       
  1755 //
       
  1756 	{
       
  1757 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1758 	iNotification = EMsvNullNotification;
       
  1759 #endif
       
  1760 
       
  1761 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  1762 
       
  1763 #ifndef _NO_SERVER_LOGGING_
       
  1764 	Log(_L("Disk %d inserted"), TInt(aDrive));
       
  1765 #endif
       
  1766 
       
  1767 	//Find the drive index of this drive
       
  1768 	TInt driveCount = iDriveList->Count();
       
  1769 	TInt index = 0;
       
  1770 	for(index=0; index < driveCount; ++index)
       
  1771 		{
       
  1772 		if((TInt)(*iDriveList)[index].driveNum == (TInt)aDrive)
       
  1773 			{
       
  1774 			break;
       
  1775 			}
       
  1776 		}
       
  1777 	
       
  1778 	//Update the drive's status.
       
  1779 	TDriveState statusDuringUpdate = EMsvInvalidDriveStatus;
       
  1780 
       
  1781 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1782 	if(aTestInsert)
       
  1783 		{
       
  1784 		statusDuringUpdate = EMsvMessageStoreCorruptStatus;
       
  1785 		(*iDriveList)[index].status = EMsvMessageStoreUnavailableStatus;
       
  1786 		}
       
  1787 	else
       
  1788 		{
       
  1789 #endif
       
  1790 		iContext->UpdateDriveStatusL(index, statusDuringUpdate);
       
  1791 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1792 		}
       
  1793 #endif
       
  1794 		
       
  1795 	TDriveState driveState = (*iDriveList)[index].status;
       
  1796 	
       
  1797 	//Check if message store was corrupt.
       
  1798 	if(EMsvMessageStoreCorruptStatus == statusDuringUpdate)
       
  1799 		{
       
  1800 		//Send notifications to all registered clients that 
       
  1801 		// media has a corrupt message store.
       
  1802 		NotifyChanged(EMsvMessageStoreCorrupt, KMsvNullIndexEntryId, TInt(aDrive));	 
       
  1803 		}
       
  1804 		
       
  1805 	if(EMsvMessageStoreNotSupportedStatus == driveState)
       
  1806 		{
       
  1807 		// Send notifications to all registered clients that 
       
  1808 		// media has an unsupported version of message store.
       
  1809 		NotifyChanged(EMsvMessageStoreNotSupported, KMsvNullIndexEntryId, TInt(aDrive));		
       
  1810 		}
       
  1811 	
       
  1812 	//Check if this new disk is in a higher priority drive.
       
  1813 	//If yes, then change drive to this higher priority drive.
       
  1814 	TUint curDriveIndex = iDriveList->CurrentDriveIndex();
       
  1815 	if(index < curDriveIndex)
       
  1816 		{	   
       
  1817 		//Check if message store is available on this drive.
       
  1818 		if( EMsvMessageStoreAvailableStatus   == driveState ||
       
  1819 			EMsvMessageStoreUnavailableStatus == driveState
       
  1820 		  )
       
  1821 			{
       
  1822 			TBool isEntryRemovalRequired = EFalse;
       
  1823 			if(EMsvMessageStoreAvailableStatus == (*iDriveList)[index].status)
       
  1824 				{
       
  1825 				isEntryRemovalRequired = ETrue;
       
  1826 				}
       
  1827 
       
  1828 			iStartupState = EMsvMediaChanged;
       
  1829 			
       
  1830 			//Change the drive to this drive.
       
  1831 			User::LeaveIfError(iContext->ChangeDrive(index));
       
  1832 			
       
  1833 			iIndexDrive = (*iDriveList)[index].driveNum;
       
  1834 			
       
  1835 			//Set the current drive index as the above drive.
       
  1836 			iDriveList->SetCurrentDriveIndex(index);
       
  1837 			
       
  1838 			// Remove incomplete entries from the new drive.
       
  1839 			if(isEntryRemovalRequired)
       
  1840 				{
       
  1841 				iContext->GetInPreparationIds((*iDriveList)[index].driveId);			
       
  1842 				if (iContext->Remove().Count())
       
  1843 					{
       
  1844 					RemoveEntry(KMsvNullIndexEntryId);
       
  1845 					}
       
  1846 				}
       
  1847 			}
       
  1848 		}
       
  1849 	//If not, then we need to send a notification only if the disk
       
  1850 	//has a valid message store.
       
  1851 	else
       
  1852 		{
       
  1853 		//Check if message store is available on this drive.
       
  1854 		if(EMsvMessageStoreAvailableStatus == driveState)
       
  1855 			{
       
  1856 			//Attach the database in the drive.
       
  1857 			iContext->IndexAdapter()->AddDriveL(index);
       
  1858 			
       
  1859 			iContext->GetInPreparationIds((*iDriveList)[index].driveId);			
       
  1860 			if (iContext->Remove().Count())
       
  1861 				{
       
  1862 				RemoveEntry(KMsvNullIndexEntryId);
       
  1863 				}
       
  1864 					
       
  1865 			//Send the notification to all registered clients that they need to 
       
  1866 			//refresh their view of messaging.
       
  1867 			NotifyChanged(EMsvRefreshMessageView, KMsvNullIndexEntryId, TInt(aDrive));
       
  1868 			}
       
  1869 		}
       
  1870 	
       
  1871 	iStartupState = EMsvNullNotification;
       
  1872 	iContext->IndexAdapter()->SetErrorState(KErrNone);  
       
  1873 	}
       
  1874 
       
  1875 
       
  1876 
       
  1877 
       
  1878 void CMsvServer::DiskChanged(const TDriveUnit& aDrive)
       
  1879 	{
       
  1880 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1881 	iNotification = EMsvNullNotification;
       
  1882 #endif
       
  1883 
       
  1884 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  1885 
       
  1886 #ifndef _NO_SERVER_LOGGING_
       
  1887 	Log(_L("Disk %d changed"), TInt(aDrive));
       
  1888 #endif
       
  1889 
       
  1890 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1891 	TRAPD(err, DoDiskRemovedL(aDrive, EFalse));
       
  1892 #else
       
  1893 	TRAPD(err, DoDiskRemovedL(aDrive));
       
  1894 #endif
       
  1895 	TRAP_IGNORE(UpdateRepositoryL());
       
  1896 	if(KErrNone != err)
       
  1897 		{
       
  1898 		// Send change drive notification.
       
  1899 		NotifyChanged(EMsvUnableToProcessDiskNotification, KMsvNullIndexEntryId, TInt(aDrive), 0);
       
  1900 		}
       
  1901 	iContext->IndexAdapter()->SetErrorState(KErrNone);
       
  1902 	}
       
  1903 
       
  1904 
       
  1905 
       
  1906 /*
       
  1907  * UpdateDriveStatus()
       
  1908  * @param TDriveUnit& : Drive information.
       
  1909  * @param TDriveStatus: New status of the drive.
       
  1910  *
       
  1911  * The function is called by CMsvCopyStoreOperation and 
       
  1912  * CMsvDeleteStoreOperation to update the target drive status 
       
  1913  * after completion of copying/deleting message store.
       
  1914  */
       
  1915 void CMsvServer::UpdateDriveStatusL(const TDriveUnit& aDrive, TDriveState aStatus)
       
  1916 	{
       
  1917 	TUint driveIndex;
       
  1918 	// If the drive is not present in the preferred drive list.
       
  1919 	if(KErrNotFound == iDriveList->GetDriveIndex(TDriveNumber(TInt(aDrive)), driveIndex))
       
  1920 		{
       
  1921 		return;
       
  1922 		}
       
  1923 	
       
  1924 	// Update the drive status.
       
  1925 	iDriveList->UpdateDriveStatusL(driveIndex, aStatus);		
       
  1926 		
       
  1927 	// Drive should be available for viewing.
       
  1928 	if(EMsvMessageStoreAvailableStatus == aStatus)
       
  1929 		{	   
       
  1930 		TUint curDriveIndex = iDriveList->CurrentDriveIndex();
       
  1931 		
       
  1932 		// Check if the new drive can be the current drive.
       
  1933 		if(driveIndex < curDriveIndex)
       
  1934 			{
       
  1935 			//Change the drive to this drive.
       
  1936 			User::LeaveIfError(iContext->ChangeDrive(driveIndex));
       
  1937 			
       
  1938 			iIndexDrive = (*iDriveList)[driveIndex].driveNum;
       
  1939 			
       
  1940 			//Set the current drive index as the above drive.
       
  1941 			iDriveList->SetCurrentDriveIndex(driveIndex);
       
  1942 			
       
  1943 			// Current drive changed, update the cenrep.
       
  1944 			UpdateRepositoryL();
       
  1945 			}
       
  1946 		else
       
  1947 			{
       
  1948 			iContext->IndexAdapter()->AddDriveL(driveIndex);
       
  1949 			
       
  1950 			//Send the notification to all registered clients that they need to 
       
  1951 			//refresh their view of messaging.
       
  1952 			NotifyChanged(EMsvRefreshMessageView, KMsvNullIndexEntryId, TInt(aDrive));
       
  1953 			}
       
  1954 
       
  1955 		// Remove incomplete entries from the new drive.
       
  1956 		iContext->GetInPreparationIds((*iDriveList)[driveIndex].driveId);		   
       
  1957 		if (iContext->Remove().Count())
       
  1958 			{
       
  1959 			RemoveEntry(KMsvNullIndexEntryId);
       
  1960 			}
       
  1961 		}
       
  1962 	}
       
  1963 	
       
  1964 		
       
  1965 	
       
  1966 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1967 void CMsvServer::ResetRepositoryL()
       
  1968 	{
       
  1969 	CRepository* repository = CRepository::NewL(KUidConfigFile);
       
  1970 	
       
  1971 	// Reset everything in the repository. Default values supplied will be
       
  1972 	// filled in.
       
  1973 	User::LeaveIfError(repository->Reset());
       
  1974 	delete repository;
       
  1975 	}
       
  1976 
       
  1977 #endif	  // #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  1978 
       
  1979 
       
  1980 
       
  1981 #else	   // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1982 
       
  1983 
       
  1984 
       
  1985 EXPORT_C void CMsvServer::CreateIndexL(TBool aSync)
       
  1986 //
       
  1987 // Creates the index, either loading it from file or creating a new file/index
       
  1988 //
       
  1989 	{
       
  1990 	__ASSERT_DEBUG(iNewContext == NULL, PanicServer(EMsvNewContextExists));
       
  1991 
       
  1992 	TDriveUnit drive(iSystemDrive);
       
  1993 
       
  1994 	// Create the new context
       
  1995 	DeleteNewContext();
       
  1996 	iNewContext = CMsvIndexContext::NewL(*this, *this);
       
  1997 
       
  1998 	// Get the Message Server configuration
       
  1999 	TInt error = iNewContext->LoadStoreConfig(ETrue);
       
  2000 	iStartupState = EMsvNullNotification;
       
  2001 
       
  2002 	if (!error)
       
  2003 		{
       
  2004 		drive = iNewContext->Config().iDrive;
       
  2005 		iIndexDrive = drive;
       
  2006 
       
  2007 		// Check the drive is available and has correct Id
       
  2008 		TVolumeInfo volume;
       
  2009 		if (iFs.Volume(volume, TInt(drive)) != KErrNone)
       
  2010 			{
       
  2011 #ifndef _NO_SERVER_LOGGING_
       
  2012 			Log(_L("The media is not available - using default"));
       
  2013 #endif
       
  2014 			// The media is not available - use default
       
  2015 			iStartupState = EMsvMediaUnavailable;
       
  2016 			drive = iSystemDrive;
       
  2017 			}
       
  2018 		iNewContext->CreateIndexL(drive, aSync);
       
  2019 		return;
       
  2020 		}
       
  2021 	else if (error == KErrInUse)
       
  2022 		{
       
  2023 		iIndexDrive = drive;
       
  2024 		iNewContext->CreateIndexL(drive, aSync);
       
  2025 		return;
       
  2026 		}
       
  2027 
       
  2028 	User::Leave(error);
       
  2029 	}
       
  2030 	
       
  2031 	
       
  2032 
       
  2033 	
       
  2034 EXPORT_C TInt CMsvServer::ChangeDrive(TInt aDrive, TRequestStatus* aStatus)
       
  2035 //
       
  2036 // Reload the Message Store from the specified drive
       
  2037 // If aStatus is null the index is loaded synchronously
       
  2038 // On error the index is unchanged
       
  2039 //
       
  2040 	{
       
  2041 	TRAPD(error, DoChangeDriveL(aDrive, aStatus));
       
  2042 	if (error)
       
  2043 		DeleteNewContext();
       
  2044 
       
  2045 	return error;
       
  2046 	}
       
  2047 	
       
  2048 	
       
  2049 	
       
  2050 
       
  2051 void CMsvServer::DoChangeDriveL(TInt aDrive, TRequestStatus* aStatus)
       
  2052 	{
       
  2053 	__ASSERT_ALWAYS(iContext->State() == TMsvIndexLoadProgress::EIndexComplete, PanicServer(EMsvLoadingInProgress));
       
  2054 	__ASSERT_ALWAYS(aDrive != iContext->Config().iDrive, User::Leave(KErrNotSupported));
       
  2055 	__ASSERT_DEBUG(iNewContext == NULL, PanicServer(EMsvNewContextExists));
       
  2056 
       
  2057 	if(iSearchSortCacheManager)
       
  2058 		{   
       
  2059 		iSearchSortCacheManager->ResetSearchSortCache();
       
  2060 		}
       
  2061 	iContext->IndexAdapter()->GetDbAdapter()->ClearDBContentsL();
       
  2062 
       
  2063 	// Delete any existing context
       
  2064 	DeleteNewContext();
       
  2065 	iNewContext = CMsvIndexContext::NewL(*this, *this);
       
  2066 	iNewContext->LoadStoreConfig(ETrue);
       
  2067 	iIndexDrive = aDrive;
       
  2068 
       
  2069 	if (aStatus)
       
  2070 		{
       
  2071 #ifndef _NO_SERVER_LOGGING_
       
  2072 		Log(_L("Changing drive asynchronously %d"), aDrive);
       
  2073 #endif
       
  2074 		// Load index asynchronously - will signal observer when complete
       
  2075 		iNewContext->CreateIndexL(aDrive, *aStatus);
       
  2076 		}
       
  2077 	else
       
  2078 		{
       
  2079 #ifndef _NO_SERVER_LOGGING_
       
  2080 		Log(_L("Changing drive synchronously %d"), aDrive);
       
  2081 #endif
       
  2082 		// Load index synchronously
       
  2083 		iNewContext->CreateIndexL(aDrive, ETrue);
       
  2084 
       
  2085 		// Delete the context - only relevant if an error occurs
       
  2086 		DeleteNewContext();
       
  2087 		User::LeaveIfError(iLoadError);
       
  2088 		}
       
  2089 	}
       
  2090 	
       
  2091 
       
  2092 
       
  2093 
       
  2094 void CMsvServer::BuildDefaultIniFileL(TMsvConfig& aConfig)
       
  2095 	{
       
  2096 	RFs fileSession;
       
  2097 	fileSession.Connect();
       
  2098 
       
  2099 	TInt error;
       
  2100 	TVolumeInfo volume;
       
  2101 	TUint uniqueId = 0;
       
  2102 	TChar driveChar= fileSession.GetSystemDriveChar();
       
  2103 	
       
  2104 	TBuf<2> systemDrive;
       
  2105 	systemDrive.Append(driveChar);
       
  2106 	systemDrive.Append(KDriveDelimiter);
       
  2107 	TDriveUnit driveUnit(systemDrive);
       
  2108 
       
  2109 	error = fileSession.Volume(volume, TInt(driveUnit));
       
  2110 	if (!error)
       
  2111 		{
       
  2112 		uniqueId = volume.iUniqueID;
       
  2113 		}
       
  2114 	else
       
  2115 		{
       
  2116 		User::Leave(error);
       
  2117 		}
       
  2118 
       
  2119 	TPath pathName(systemDrive);
       
  2120 	pathName.Append(KServerINIFile);
       
  2121 	CDictionaryFileStore *store=CDictionaryFileStore::OpenLC(fileSession, pathName, KNullUid);
       
  2122 
       
  2123 	RDictionaryWriteStream stream;
       
  2124 	stream.AssignLC(*store, KUidMsvMessageDriveStream);
       
  2125 
       
  2126 	//Assign the default values
       
  2127 	stream.WriteUint8L(KMsvMessageDriveStreamVersionNumber); // version number
       
  2128 	stream << systemDrive;
       
  2129 	stream.WriteUint32L(uniqueId);
       
  2130 	stream.WriteInt8L(EFalse);
       
  2131 
       
  2132 	stream.CommitL();
       
  2133 	store->CommitL();
       
  2134 	CleanupStack::PopAndDestroy(2,store); // stream, store
       
  2135 
       
  2136 	// update the values in aConfig
       
  2137 	aConfig.iDrive = driveUnit;
       
  2138 	aConfig.iUniqueID = uniqueId;
       
  2139 	aConfig.iDebug = EFalse;
       
  2140 	return; // there's no need to try to read further
       
  2141 			// values since we just made them up and
       
  2142 			// stored them here to replace the corrupt
       
  2143 			// ini file
       
  2144 	}
       
  2145 
       
  2146 
       
  2147 
       
  2148 
       
  2149 void CMsvServer::CurrentConfigL(RFs& aFs, TMsvConfig& aConfig)
       
  2150 	{
       
  2151 	TChar driveChar= aFs.GetSystemDriveChar();
       
  2152 	TBuf<2> systemDrive;
       
  2153 	systemDrive.Append(driveChar);
       
  2154 	systemDrive.Append(KDriveDelimiter);
       
  2155 	
       
  2156 	TDriveUnit driveUnit(systemDrive);  
       
  2157 	aConfig.iDrive = driveUnit;
       
  2158 	aConfig.iUniqueID = 0;
       
  2159 	aConfig.iDebug = EFalse;
       
  2160 
       
  2161 	TPath pathName(driveUnit.Name());
       
  2162 	pathName.Append(KServerINIFile);
       
  2163 	// try to open system ini
       
  2164 	CDictionaryFileStore* store = NULL;
       
  2165 	TUint unused;
       
  2166 	TInt err=aFs.Att(pathName, unused);
       
  2167 	if(err==KErrNone)
       
  2168 		{
       
  2169 		TRAPD(openIniErr,store = CDictionaryFileStore::OpenL(aFs, pathName, KNullUid));
       
  2170 		if (openIniErr == KErrCorrupt)
       
  2171 			{
       
  2172 			// The ini file has been corrupted. Delete it and create a new one
       
  2173 			aFs.Delete(pathName);
       
  2174 			RFile newIniFile;
       
  2175 			User::LeaveIfError(newIniFile.Create(aFs, pathName, EFileWrite));
       
  2176 			newIniFile.Close();
       
  2177 			BuildDefaultIniFileL(aConfig);
       
  2178 			return;
       
  2179 			}
       
  2180 		User::LeaveIfError(openIniErr);
       
  2181 		CleanupStack::PushL(store);
       
  2182 
       
  2183 		// get configuration from system ini
       
  2184 		if (store->IsPresentL(KUidMsvMessageDriveStream))
       
  2185 			{
       
  2186 			RDictionaryReadStream readStream;
       
  2187 			readStream.OpenLC(*store, KUidMsvMessageDriveStream);
       
  2188 			TInt version = readStream.ReadInt8L();
       
  2189 			// Check the drive stream version number. If invalid,
       
  2190 			// rebuild the ini file
       
  2191 			if (version > KMsvMessageDriveStreamVersionNumber)
       
  2192 				{
       
  2193 				//cleanup the corrupted info
       
  2194 				CleanupStack::PopAndDestroy(2, store);
       
  2195 
       
  2196 				//create a new ini file
       
  2197 				RFs fileSession;
       
  2198 				fileSession.Connect();
       
  2199 
       
  2200 				TInt error;
       
  2201 				TVolumeInfo volume;
       
  2202 				TUint uniqueId = 0;
       
  2203 				TDriveUnit driveUnit(systemDrive);
       
  2204 				error = fileSession.Volume(volume, TInt(driveUnit));
       
  2205 				if (!error)
       
  2206 					{
       
  2207 					uniqueId = volume.iUniqueID;
       
  2208 					}
       
  2209 				else
       
  2210 					{
       
  2211 					User::Leave(error);
       
  2212 					}
       
  2213 
       
  2214 				CDictionaryFileStore *store=CDictionaryFileStore::OpenLC(fileSession, pathName, KNullUid);
       
  2215 				RDictionaryWriteStream stream;
       
  2216 				stream.AssignLC(*store, KUidMsvMessageDriveStream);
       
  2217 
       
  2218 				//Assign the default values
       
  2219 				stream.WriteUint8L(KMsvMessageDriveStreamVersionNumber); // version number
       
  2220 				stream << systemDrive;
       
  2221 				stream.WriteUint32L(uniqueId);
       
  2222 				stream.WriteInt8L(EFalse);
       
  2223 
       
  2224 				stream.CommitL();
       
  2225 				store->CommitL();
       
  2226 				CleanupStack::PopAndDestroy(2,store); // stream, store
       
  2227 
       
  2228 				// update the values in aConfig
       
  2229 				aConfig.iDrive = driveUnit;
       
  2230 				aConfig.iUniqueID = uniqueId;
       
  2231 				aConfig.iDebug = EFalse;
       
  2232 				return; // there's no need to try to read further
       
  2233 						// values since we just made them up and
       
  2234 						// stored them here to replace the corrupt
       
  2235 						// ini file
       
  2236 				}
       
  2237 
       
  2238 			TBuf<2> drive;
       
  2239 			readStream >> drive;
       
  2240 			aConfig.iDrive = drive;
       
  2241 
       
  2242 			// The drive Id didn't exist in earlier versions
       
  2243 			if (version > 1)
       
  2244 				aConfig.iUniqueID = readStream.ReadUint32L();
       
  2245 
       
  2246 			// This debug frig wasn't in earlier versions
       
  2247 			if (version > 2)
       
  2248 				aConfig.iDebug = readStream.ReadInt8L();
       
  2249 
       
  2250 			CleanupStack::PopAndDestroy(); // readStream
       
  2251 			}
       
  2252 
       
  2253 		CleanupStack::PopAndDestroy(); // store
       
  2254 		}
       
  2255 	// remember what we loaded, so we don't have to save it if it doesn't change.
       
  2256 	// also means we don't have the defaults as they never change.
       
  2257 	aConfig.iDriveAsLoaded=aConfig.iDrive;
       
  2258 	aConfig.iDebugAsLoaded=aConfig.iDebug;
       
  2259 	aConfig.iUniqueIDAsLoaded=aConfig.iUniqueID;
       
  2260 	}
       
  2261 
       
  2262 
       
  2263 
       
  2264 
       
  2265 TBool CMsvServer::DiskRemoved(const TDriveUnit& aDrive)
       
  2266 	{
       
  2267 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  2268 #ifndef _NO_SERVER_LOGGING_
       
  2269 	Log(_L("Disk %d removed"), TInt(aDrive));
       
  2270 #endif
       
  2271 	if(iContext->IndexAdapter()->ErrorState() != KMsvIndexRestore)
       
  2272 		{
       
  2273 		NotifyChanged(EMsvMediaUnavailable, KMsvNullIndexEntryId, TInt(aDrive));
       
  2274 		}
       
  2275 	else
       
  2276 		{
       
  2277 		iReleasedForRestore = ETrue;
       
  2278 		}
       
  2279 	iContext->IndexAdapter()->SetErrorState(KMsvMediaUnavailable);
       
  2280 	iContext->IndexAdapter()->DeleteDbAdapter();
       
  2281 
       
  2282 	iStartupState = EMsvMediaUnavailable;
       
  2283 	return ETrue;
       
  2284 	}
       
  2285 
       
  2286 
       
  2287 
       
  2288 
       
  2289 TBool CMsvServer::DiskInserted(const TDriveUnit& aDrive)
       
  2290 	{
       
  2291 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  2292 
       
  2293 #ifndef _NO_SERVER_LOGGING_
       
  2294 	Log(_L("Disk %d inserted"), TInt(aDrive));
       
  2295 #endif
       
  2296 	if(!iReleasedForRestore)
       
  2297 		{
       
  2298 		NotifyChanged(EMsvMediaAvailable, KMsvNullIndexEntryId, TInt(aDrive));
       
  2299 		}
       
  2300 	else
       
  2301 		{
       
  2302 		iReleasedForRestore = EFalse;
       
  2303 		}
       
  2304 
       
  2305 	iContext->IndexAdapter()->SetErrorState(KErrNone);
       
  2306 
       
  2307 	//Need to re-open the DB when media is available (EMsvMediaAvailable).
       
  2308 	//Get current drive
       
  2309 	TInt currentDrive = 0;
       
  2310 	TRAPD(err, currentDrive = MessageServer::CurrentDriveL(iFs));
       
  2311 	if (err != KErrNone)
       
  2312 		{
       
  2313 		return EFalse;
       
  2314 		}
       
  2315 	
       
  2316 	//Get system drive
       
  2317 	TChar charDrive = FileSession().GetSystemDriveChar();
       
  2318 	TInt defaultDrive = 0;
       
  2319 	iFs.CharToDrive(charDrive, defaultDrive);
       
  2320 	TChar driveToOpen;
       
  2321 	iFs.DriveToChar(currentDrive, driveToOpen);
       
  2322 		
       
  2323 	if(currentDrive != defaultDrive)
       
  2324 		{
       
  2325 		TBuf<2> systemDrive;
       
  2326 		systemDrive.Append(driveToOpen);
       
  2327 		systemDrive.Append(KDriveDelimiter);
       
  2328 		TPath pathName(systemDrive);
       
  2329 		pathName.Append(KMsvDbFile);
       
  2330 
       
  2331 		//Re-open the DB
       
  2332 		TRAPD(error, iContext->IndexAdapter()->OpenclosedL(pathName));
       
  2333 	
       
  2334 		if(error)
       
  2335 			{
       
  2336 			#ifndef _NO_SERVER_LOGGING_
       
  2337 				Log(_L("Unable to re-open DB  "));
       
  2338 			#endif  
       
  2339 			} 
       
  2340 		}
       
  2341 
       
  2342 	iStartupState = EMsvNullNotification;
       
  2343 	return ETrue;
       
  2344 	}
       
  2345 
       
  2346 
       
  2347 
       
  2348 
       
  2349 TBool CMsvServer::DiskChanged(const TDriveUnit& aDrive, TUint)
       
  2350 	{
       
  2351 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  2352 
       
  2353 #ifndef _NO_SERVER_LOGGING_
       
  2354 	Log(_L("Disk %d changed"), TInt(aDrive));
       
  2355 #endif
       
  2356 
       
  2357 	NotifyChanged(EMsvMediaIncorrect, KMsvNullIndexEntryId, TInt(aDrive));
       
  2358 	iContext->IndexAdapter()->SetErrorState(KMsvMediaIncorrect);
       
  2359 	iStartupState = EMsvMediaIncorrect;
       
  2360 	return ETrue;
       
  2361 	}
       
  2362 
       
  2363 
       
  2364 
       
  2365 void CMsvServer::ContextComplete(TInt aError, TBool aRunMailInit)
       
  2366 //
       
  2367 // The context has completed successfully or with failure
       
  2368 //
       
  2369 	{
       
  2370 #ifndef _NO_SERVER_LOGGING_
       
  2371 	Log(_L("Context complete with error %d"), aError);
       
  2372 #endif
       
  2373 
       
  2374 	if (!aError)
       
  2375 		{
       
  2376 		// Stop disk change notifications
       
  2377 		iNotify->Cancel();
       
  2378 
       
  2379 		// Save the new configuration
       
  2380 		iNewContext->LoadStoreConfig(EFalse); // Ignore the error
       
  2381 		TBool startup = iContext == NULL;
       
  2382 
       
  2383 		CMsvIndexContext* oldContext = iContext;
       
  2384 		iContext = iNewContext;
       
  2385 		iNewContext = NULL;
       
  2386 
       
  2387 #ifndef _NO_SERVER_LOGGING_
       
  2388 		Log(_L("Deleting iBackup"));
       
  2389 #endif
       
  2390 		if(iBackup == NULL)
       
  2391 			{
       
  2392 			// To Gracefully handle and to register with the backup server.
       
  2393 			TRAP_IGNORE(iBackup=CMsvBackupHandler::NewL(*this));
       
  2394 			}
       
  2395 
       
  2396 		// Check for presence of MailInit not completed flag
       
  2397 		iFs.SetSessionToPrivate(iContext->Config().iDrive);
       
  2398 		TUint unused;
       
  2399 		TBool initNotCompleted = (iFs.Att(KMsvStoreInitFileName, unused)!=KErrNotFound);
       
  2400 		if ((initNotCompleted || aRunMailInit) && !(iDebug || iContext->Config().iDebug))
       
  2401 			RunMailInitExe();
       
  2402 
       
  2403 
       
  2404 		// Send index ready notification
       
  2405 		NotifyChanged(EMsvIndexLoaded);
       
  2406 
       
  2407 		if (!startup)
       
  2408 			{
       
  2409 			// Send disk change notification
       
  2410 			NotifyChanged(EMsvMediaChanged, KMsvNullIndexEntryId, TInt(oldContext->Config().iDrive), TInt(iContext->Config().iDrive));
       
  2411 			}
       
  2412 		else
       
  2413 			{
       
  2414 			// Send disk change notifications if drive changed
       
  2415 			if (iStartupState != EMsvNullNotification && TInt(iIndexDrive) != TInt(iContext->Config().iDrive))
       
  2416 				{
       
  2417 				NotifyChanged(iStartupState, KMsvNullIndexEntryId, TInt(iIndexDrive));
       
  2418 				NotifyChanged(EMsvMediaChanged, KMsvNullIndexEntryId, TInt(iIndexDrive), TInt(iContext->Config().iDrive));
       
  2419 				}
       
  2420 
       
  2421 			}
       
  2422 
       
  2423 		// Reset the index error state
       
  2424 		iContext->IndexAdapter()->SetErrorState(KErrNone);
       
  2425 		iStartupState = EMsvNullNotification;
       
  2426 		delete oldContext;
       
  2427 		}
       
  2428 
       
  2429 	if (iContext && iContext->Config().iDrive.Name().CompareF(iSystemDrive) != 0 && !iNotify->IsActive())
       
  2430 		{
       
  2431 		// Restart disk change notifications
       
  2432 		iNotify->Start(iContext->Config().iDrive, iContext->Config().iUniqueID);
       
  2433 		}
       
  2434 
       
  2435 	// Remember the error
       
  2436 	iLoadError = aError;
       
  2437 	}
       
  2438 
       
  2439 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2440 
       
  2441 
       
  2442 
       
  2443 
       
  2444 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2445 void CMsvServer::RunMailInitExe(TDriveNumber aDriveNum)
       
  2446 #else
       
  2447 void CMsvServer::RunMailInitExe()
       
  2448 #endif
       
  2449 //
       
  2450 //
       
  2451 //
       
  2452 	{
       
  2453 #ifndef _NO_SERVER_LOGGING_
       
  2454 	Log(_L("Running mailinit"));
       
  2455 #endif
       
  2456 	_LIT8(KMsvStoreInitTestData,"StoreInit");
       
  2457 	RFile storeInitFile;
       
  2458 
       
  2459 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT) 
       
  2460 	iFs.SetSessionToPrivate(aDriveNum);
       
  2461 #else
       
  2462 	iFs.SetSessionToPrivate(iContext->Config().iDrive);
       
  2463 #endif
       
  2464 
       
  2465 	if (storeInitFile.Replace(iFs, KMsvStoreInitFileName, EFileShareAny|EFileWrite)==KErrNone)
       
  2466 		storeInitFile.Write(KMsvStoreInitTestData);
       
  2467 	storeInitFile.Close();
       
  2468 	// NOTE! MailInit.exe MUST delete this file otherwise MailInit will be run each time the
       
  2469 	//	   message server is started.
       
  2470 	// this note is only true for releases before v9.0
       
  2471 
       
  2472 	_LIT(KMsvPostInitialisationSearchPattern, "*MAILINIT*");
       
  2473 	_LIT(KMsvPostInitialisationProcessPattern, "*");
       
  2474 	RProcess p;
       
  2475 	TFindProcess finder;
       
  2476 #define CREATE_PROCESS_OR_THREAD() p.Create(KMsvPostInitialisationExe, TPtr(NULL,0), TUidType(KNullUid, KNullUid, KMsvMailInitExeUid))
       
  2477 
       
  2478 
       
  2479 #ifndef _NO_SERVER_LOGGING_
       
  2480 	Log(_L("Checking for mailinit process/thread"));
       
  2481 #endif
       
  2482 
       
  2483 	TFullName fullName;
       
  2484 	TBool found = EFalse;
       
  2485 	finder.Find(KMsvPostInitialisationProcessPattern);
       
  2486 	while (finder.Next(fullName) == KErrNone && !found)
       
  2487 		{
       
  2488 		fullName.UpperCase();
       
  2489 		if (fullName.Match(KMsvPostInitialisationSearchPattern) != KErrNotFound)
       
  2490 			{
       
  2491 #ifndef _NO_SERVER_LOGGING_
       
  2492 			Log(_L("Mailinit (%S) found"), &fullName);
       
  2493 #endif
       
  2494 			found = ETrue;
       
  2495 			break;
       
  2496 			}
       
  2497 		}
       
  2498 
       
  2499 	if (!found)
       
  2500 		{
       
  2501 #ifndef _NO_SERVER_LOGGING_
       
  2502 		Log(_L("Mailinit not detected, running"));
       
  2503 #endif
       
  2504 		if (CREATE_PROCESS_OR_THREAD() == KErrNone)
       
  2505 			{
       
  2506 			p.Resume();
       
  2507 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT) 
       
  2508 			iMailinitWaiter->WaitFor(p, aDriveNum);
       
  2509 #else
       
  2510 			iMailinitWaiter->WaitFor(p, (TDriveNumber) (TInt)(iContext->Config().iDrive));
       
  2511 #endif		  
       
  2512 
       
  2513 #ifndef _NO_SERVER_LOGGING_
       
  2514 			Log(_L("Mailinit run"));
       
  2515 #endif
       
  2516 			}
       
  2517 		}
       
  2518 	}
       
  2519 
       
  2520 
       
  2521 CSession2* CMsvServer::DoNewSessionL(const RMessage2 &aMessage)
       
  2522 //
       
  2523 //
       
  2524 //
       
  2525 	{
       
  2526 	if (iCloseServer)
       
  2527 		{
       
  2528 #ifndef _NO_SERVER_LOGGING_
       
  2529 		Log(_L("New session requested whilst waiting to close!"));
       
  2530 #endif
       
  2531 		User::Leave(KErrServerBusy);
       
  2532 		}
       
  2533 
       
  2534 	// create the session
       
  2535 	CMsvServerSession* ses = CMsvServerSession::NewL(*this, aMessage);
       
  2536 
       
  2537 #ifndef _NO_SERVER_LOGGING_
       
  2538 	Log(_L("New session created for process %S"), &ses->ProcessName());
       
  2539 #endif
       
  2540 
       
  2541 #ifdef MSG_SERV_AUTO_CLOSE
       
  2542 	// cancel the close down timer
       
  2543 	iCloseTimer->Cancel();
       
  2544 #endif
       
  2545 
       
  2546 	return ses;
       
  2547 	}
       
  2548 
       
  2549 
       
  2550 CSession2 *CMsvServer::NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
       
  2551 	{
       
  2552 	// check we're the right version
       
  2553 	TVersion v(KMsvServerMajorVersionNumber,KMsvServerMinorVersionNumber,KMsvServerBuildVersionNumber);
       
  2554 	if (!User::QueryVersionSupported(v,aVersion))
       
  2555 		User::Leave(KErrNotSupported);
       
  2556 
       
  2557 	// create the index if not already done
       
  2558 	return ((CMsvServer*)this)->DoNewSessionL(aMessage);
       
  2559 	}
       
  2560 
       
  2561 void CMsvServer::CompleteBulkTransaction(void)
       
  2562 	{
       
  2563 	iContext->IndexAdapter()->CommitNonCommitedEntries();
       
  2564 	TRAP_IGNORE(NotifyChangedBulkL());
       
  2565 	}
       
  2566 
       
  2567 void CMsvServer::NotifyChangedBulkL()
       
  2568 	{
       
  2569 	// send notifications for the created entries
       
  2570 	DoNotifyChangedBulkL(EMsvEntriesCreated, *iBulkCreationSelection);
       
  2571 
       
  2572 
       
  2573 	// send notifications for the changed entries
       
  2574 	CMsvEntrySelection* selection = new(ELeave) CMsvEntrySelection();
       
  2575 	CleanupStack::PushL(selection);
       
  2576 	TInt bulkChangeCount = iBulkChangeSelection->Count();
       
  2577 	selection->SetReserveL(bulkChangeCount);
       
  2578 
       
  2579 	// no need to notify entries which have already been notified (by the create notification)
       
  2580 	TMsvId changedId = 0;
       
  2581 	for (TInt ii=0; ii<bulkChangeCount; ++ii)
       
  2582 		{
       
  2583 		changedId = iBulkChangeSelection->At(ii);
       
  2584 		if (iBulkCreationSelection->Find(changedId) == KErrNotFound)
       
  2585 			{
       
  2586 			selection->AppendL(changedId);
       
  2587 			}
       
  2588 		}
       
  2589 
       
  2590 	DoNotifyChangedBulkL(EMsvEntriesChanged, *selection);
       
  2591 
       
  2592 	iBulkCreationSelection->Reset();
       
  2593 	iBulkChangeSelection->Reset();
       
  2594 	CleanupStack::PopAndDestroy(selection);
       
  2595 	}
       
  2596 
       
  2597 void CMsvServer::DoNotifyChangedBulkL(TMsvServerChangeNotificationType aChangeType, const CMsvEntrySelection& aEntriesToNotify)
       
  2598 	{
       
  2599 	TInt entriesToNotifyCount = aEntriesToNotify.Count();
       
  2600 	if( entriesToNotifyCount > 0 )
       
  2601 		{
       
  2602 		//Check whether all entries has the same parent id
       
  2603 		//If not send individual notifications
       
  2604 		CMsvEntrySelection* selection = new(ELeave) CMsvEntrySelection();
       
  2605 		CleanupStack::PushL(selection);
       
  2606 
       
  2607 		// Reserve the maximum space required - avoid leaves later on.
       
  2608 		selection->SetReserveL(entriesToNotifyCount);
       
  2609 
       
  2610 		TMsvId id;
       
  2611 		TMsvId parentId = KMsvNullIndexEntryId;
       
  2612 		TMsvId tempParentId = KMsvNullIndexEntryId;
       
  2613 		TMsvEntry* entryPtr;
       
  2614 		TInt error;
       
  2615 		TBool foundOne(EFalse);
       
  2616 
       
  2617 		for (TInt i = 0; i < entriesToNotifyCount; ++i)
       
  2618 			{
       
  2619 			id = aEntriesToNotify.At(i);
       
  2620 			error = IndexAdapter().GetEntry(id, entryPtr);
       
  2621 			if (error == KErrNone)
       
  2622 				{
       
  2623 				tempParentId = entryPtr->Parent();
       
  2624 
       
  2625 				if (foundOne)
       
  2626 					{
       
  2627 					// We have found a previously valid entry. If this
       
  2628 					// new entry has a different parent to the previous one,
       
  2629 					// send the notifications now using the old parent and
       
  2630 					// start again with the new parent.
       
  2631 					if (tempParentId != parentId)
       
  2632 						{
       
  2633 						NotifyChanged(aChangeType, *selection, parentId);
       
  2634 						selection->Reset();
       
  2635 						parentId = tempParentId;
       
  2636 						}
       
  2637 					}
       
  2638 				else
       
  2639 					{
       
  2640 					// This is the first valid entry we have found. Store its parent
       
  2641 					// as we need to see if the next entry has the same parent as well
       
  2642 					foundOne = ETrue;
       
  2643 					parentId = tempParentId;
       
  2644 					}
       
  2645 
       
  2646 				selection->AppendL(id);
       
  2647 				}
       
  2648 			}
       
  2649 
       
  2650 		if (selection->Count() != 0)
       
  2651 			{
       
  2652 			NotifyChanged(aChangeType, *selection, parentId);
       
  2653 			}
       
  2654 
       
  2655 		CleanupStack::PopAndDestroy(selection);
       
  2656 		}
       
  2657 	}
       
  2658 
       
  2659 void CMsvServer::PoliceReadEntryL(const RMessage2& aMsg, TSecureId aOwnerId, const char* aContextText)
       
  2660 	{
       
  2661 	// The client can read the entry under following circumstances.
       
  2662 	// 1. The client has Read User Data capability.
       
  2663 	// 2. The client does not have Read User Data but owns the entry.
       
  2664 
       
  2665 	// First check if the client is trusted with Read User Data.
       
  2666 	if( !aMsg.HasCapability(ECapabilityReadUserData) )
       
  2667 		{
       
  2668 		// Client not trusted with Read User data - check that it owns the entry.
       
  2669 		if( aMsg.SecureId() != aOwnerId )
       
  2670 			{
       
  2671 			// Client missing capabilities - emit diagnostics and leave...
       
  2672 			User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, ECapabilityReadUserData, aContextText));
       
  2673 			}
       
  2674 		}
       
  2675 	}
       
  2676 
       
  2677 void CMsvServer::PoliceReadEntryL(const RMessage2& aMsg, TMsvId aId, const char* aContextText)
       
  2678 	{
       
  2679 	// The client can read the entry under following circumstances.
       
  2680 	// 1. The client has Read User Data capability.
       
  2681 	// 2. The client does not have Read User Data but owns the entry.
       
  2682 
       
  2683 	// First check if the client is trusted with Read User Data.
       
  2684 	if( !aMsg.HasCapability(ECapabilityReadUserData) )
       
  2685 		{
       
  2686 		// Client not trusted with Read User data - check that it owns the entry.
       
  2687 		TMsvEntry* entryPtrNotUsed;
       
  2688 		TSecureId ownerId;
       
  2689 		TInt error = IndexAdapter().GetEntry(aId, entryPtrNotUsed, ownerId);
       
  2690 		if( aMsg.SecureId() != ownerId )
       
  2691 			{
       
  2692 			// Client missing capabilities - emit diagnostics and leave...
       
  2693 			User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, ECapabilityReadUserData, aContextText));
       
  2694 			}
       
  2695 		}
       
  2696 	}
       
  2697 
       
  2698 void CMsvServer::PoliceCreateEntryL(const RMessage2& aMsg, TMsvEntry aEntry, TBool& aIsLocal, const char* aContextText)
       
  2699 	{
       
  2700 	// Get the parent entry info...
       
  2701 	CMsvIndexAdapter::TMsvServerEntryInfo info;
       
  2702 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aEntry.Parent(), info));
       
  2703 	// Change the MTM and type to that specified in aEntry...
       
  2704 	info.iType  = aEntry.iType;
       
  2705 	info.iMtm   = aEntry.iMtm;
       
  2706 
       
  2707 	PoliceCreateModifyEntryL(aMsg, info, ETrue, aIsLocal, aContextText);
       
  2708 	}
       
  2709 
       
  2710 void CMsvServer::PoliceModifyEntryL(const RMessage2& aMsg, TMsvEntry aEntry, TBool& aIsLocal, const char* aContextText)
       
  2711 	{
       
  2712 	// Get the entry info...
       
  2713 	CMsvIndexAdapter::TMsvServerEntryInfo info;
       
  2714 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aEntry.Id(), info));
       
  2715 	// Change the MTM and type to that specified in aEntry...
       
  2716 	info.iType  = aEntry.iType;
       
  2717 	info.iMtm   = aEntry.iMtm;
       
  2718 
       
  2719 	PoliceCreateModifyEntryL(aMsg, info, EFalse, aIsLocal, aContextText);
       
  2720 	}
       
  2721 
       
  2722 void CMsvServer::PoliceModifyEntryL(const RMessage2& aMsg, TMsvId aId, TBool& aIsLocal, const char* aContextText)
       
  2723 	{
       
  2724 	// Get the entry info...
       
  2725 	CMsvIndexAdapter::TMsvServerEntryInfo info;
       
  2726 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aId, info));
       
  2727 	PoliceCreateModifyEntryL(aMsg, info, EFalse, aIsLocal, aContextText);
       
  2728 	}
       
  2729 
       
  2730 void CMsvServer::PoliceModifyEntryL(const RMessage2& aMsg, TMsvId aId, const char* aContextText)
       
  2731 	{
       
  2732 	TBool notUsed;
       
  2733 	PoliceModifyEntryL(aMsg, aId, notUsed, aContextText);
       
  2734 	}
       
  2735 
       
  2736 
       
  2737 void CMsvServer::PoliceCreateModifyEntryL(const RMessage2& aMsg, CMsvIndexAdapter::TMsvServerEntryInfo aEntryInfo, TBool aCreate, TBool& aIsLocal, const char* aContextText)
       
  2738 	{
       
  2739 	TCapabilitySet caps;
       
  2740 
       
  2741 	// The entry is local if the service is the local service.
       
  2742 	aIsLocal = aEntryInfo.iService == KMsvLocalServiceIndexEntryId;
       
  2743 
       
  2744 	// Check if a service entry or non-service entry is being created.
       
  2745 	if( aEntryInfo.iType != KUidMsvServiceEntry && aEntryInfo.iType != KUidMsvRootEntry )
       
  2746 		{
       
  2747 		// When creating/modifying an under local service, use the entry MTM
       
  2748 		// but under a remote service, use the remote service MTM.
       
  2749 		TUid mtm = aIsLocal ? aEntryInfo.iMtm : aEntryInfo.iServiceMtm;
       
  2750 
       
  2751 		// If creating an entry, check against the parent owner ID, but modifying
       
  2752 		// an entry, check against the entry owner ID.
       
  2753 		TSecureId ownerId = aCreate ? aEntryInfo.iParentOwnerId : aEntryInfo.iEntryOwnerId;
       
  2754 
       
  2755 		// If creating an entry, the create flag depends on whether the entry
       
  2756 		// is being created under an existing message.
       
  2757 		TBool create = aCreate ? !aEntryInfo.iPartOfMessage : EFalse;
       
  2758 
       
  2759 		// Given all the info, go get the required capabilities.
       
  2760 		GetCapsEntryCreateModifyL(aMsg, aEntryInfo.iTopFolder, mtm, ownerId, create, aIsLocal, caps);
       
  2761 		}
       
  2762 	else
       
  2763 		{
       
  2764 		// Client requires write device data to create/modify a service entry.
       
  2765 		caps.SetEmpty();
       
  2766 		caps.AddCapability(ECapabilityWriteDeviceData);
       
  2767 		}
       
  2768 	// Ok, have the required capabilities - check the client capabilities
       
  2769 	TSecurityInfo clientInfo(aMsg);
       
  2770 
       
  2771 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2772 		{
       
  2773 		// Client missing capabilities - emit diagnostics and leave...
       
  2774 		caps.Remove(clientInfo.iCaps);
       
  2775 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2776 		}
       
  2777 	}
       
  2778 
       
  2779 void CMsvServer::PoliceMoveEntriesL(const RMessage2& aMsg, const CMsvEntrySelection& aSelection, TMsvId aTarget, TMsvId aSource, TBool& aTargetIsLocal, TBool& aSourceIsLocal, const char* aContextText)
       
  2780 	{
       
  2781 	// To police a move entries request, the client must be able to modify both
       
  2782 	// the target entry and the source entry. In the case of the target entry,
       
  2783 	// the client is essentially creating entries under the target entry.
       
  2784 
       
  2785 	// Checking the target is the same as for a copy...
       
  2786 
       
  2787 #if (defined SYMBIAN_USER_PROMPT_SERVICE)
       
  2788 	TRAPD(err, PoliceCopyEntriesL(aMsg, aSelection, aTarget, aTargetIsLocal, aContextText));
       
  2789 	if(err != KErrPermissionDenied)
       
  2790 		{
       
  2791 		User::LeaveIfError(err);
       
  2792 		}
       
  2793 #else
       
  2794 	PoliceCopyEntriesL(aMsg, aSelection, aTarget, aTargetIsLocal, aContextText);
       
  2795 #endif
       
  2796 	
       
  2797 	// Get the entry into the source entry...
       
  2798 	CMsvIndexAdapter::TMsvServerEntryInfo sourceInfo;
       
  2799 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aSource, sourceInfo));
       
  2800 	// Police the modification of source entry.
       
  2801 	PoliceCreateModifyEntryL(aMsg, sourceInfo, EFalse, aSourceIsLocal, aContextText);
       
  2802 #if (defined SYMBIAN_USER_PROMPT_SERVICE)
       
  2803 	if(err != KErrNone && aSourceIsLocal && aTargetIsLocal)
       
  2804 		{
       
  2805 		User::LeaveIfError(err);
       
  2806 		}
       
  2807 #endif
       
  2808 	}
       
  2809 
       
  2810 void CMsvServer::PoliceCopyEntriesL(const RMessage2& aMsg, const CMsvEntrySelection& aSelection, TMsvId aTarget, TBool& aTargetIsLocal, const char* aContextText)
       
  2811 	{
       
  2812 	// To police a copy entries request, the client must be able to modify the
       
  2813 	// target entry - essentially it is creating entries under the target entry.
       
  2814 
       
  2815 	// Get the entry info for target entry...
       
  2816 	CMsvIndexAdapter::TMsvServerEntryInfo targetInfo;
       
  2817 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aTarget, targetInfo));
       
  2818 	// The policing strategy changes slightly if the target is the outbox or a
       
  2819 	// folder under the outbox that is not part of a message.
       
  2820 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2821 	TMsvId topFolderId = UnmaskTMsvId(targetInfo.iTopFolder);
       
  2822 #else
       
  2823 	TMsvId topFolderId = targetInfo.iTopFolder;
       
  2824 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2825 	
       
  2826 	if( topFolderId == KMsvGlobalOutBoxIndexEntryId &&
       
  2827 		targetInfo.iType == KUidMsvFolderEntry && !targetInfo.iPartOfMessage )
       
  2828 		{
       
  2829 		aTargetIsLocal = ETrue;
       
  2830 		PoliceCopyMoveUnderOutboxL(aMsg, aSelection, aContextText);
       
  2831 		}
       
  2832 	else
       
  2833 		{
       
  2834 		// Police the modification of target entry. NOTE - check client can
       
  2835 		// create entries under target.
       
  2836 		PoliceCreateModifyEntryL(aMsg, targetInfo, ETrue, aTargetIsLocal, aContextText);
       
  2837 		}
       
  2838 	}
       
  2839 
       
  2840 void CMsvServer::PoliceCopyMoveUnderOutboxL(const RMessage2& aMsg, const CMsvEntrySelection& aSelection, const char* aContextText)
       
  2841 	{
       
  2842 	// The target is either the outbox itself or a folder under the outbox
       
  2843 	// that is not part of message. In this case need to police the request
       
  2844 	// against the capabilities specified by the MTM of each entry in the
       
  2845 	// seleciton as well as read/write user data.
       
  2846 	TCapabilitySet caps;
       
  2847 	caps.SetEmpty();
       
  2848 
       
  2849 	TInt count = aSelection.Count();
       
  2850 	for( TInt i=0; i<count; ++i )
       
  2851 		{
       
  2852 		TMsvEntry* entryPtr;
       
  2853 		User::LeaveIfError(iContext->IndexAdapter()->GetEntry(aSelection.At(i), entryPtr));
       
  2854 		// Get the capabilities specified by the MTM of the entry and add them
       
  2855 		// to the total required set.
       
  2856 		TCapabilitySet mtmCaps;
       
  2857 		GetCapsForMtmL(entryPtr->iMtm, mtmCaps);
       
  2858 		caps.Union(mtmCaps);
       
  2859 		}
       
  2860 	if( ProtectedFolder(KMsvGlobalOutBoxIndexEntryId) )
       
  2861 		{
       
  2862 		// The outbox is protected - need read/write user data capabilities.
       
  2863 		caps.AddCapability(ECapabilityReadUserData);
       
  2864 		caps.AddCapability(ECapabilityWriteUserData);
       
  2865 		}
       
  2866 	// Ok, have the required capabilities - check the client capabilities
       
  2867 	TSecurityInfo clientInfo(aMsg);
       
  2868 
       
  2869 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2870 		{
       
  2871 		// Client missing capabilities - emit diagnostics and leave...
       
  2872 		caps.Remove(clientInfo.iCaps);
       
  2873 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2874 		}
       
  2875 	}
       
  2876 
       
  2877 void CMsvServer::PoliceMtmTransferCommandL(const RMessage2& aMsg, TUid aMtm, const char* aContextText)
       
  2878 	{
       
  2879 	// To access the functionality of a server MTM, a client is required to be
       
  2880 	// trusted with read and write user data as well as the capabilities
       
  2881 	// specified by the server MTM.
       
  2882 	TCapabilitySet caps;
       
  2883 	GetMtmRequiredCapabilitiesL(aMtm, caps);
       
  2884 	caps.AddCapability(ECapabilityReadUserData);
       
  2885 	caps.AddCapability(ECapabilityWriteUserData);
       
  2886 
       
  2887 	// Ok, have the required capabilities - check the client capabilities
       
  2888 	TSecurityInfo clientInfo(aMsg);
       
  2889 
       
  2890 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2891 		{
       
  2892 		// Client missing capabilities - emit diagnostics and leave...
       
  2893 		caps.Remove(clientInfo.iCaps);
       
  2894 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2895 		}
       
  2896 	}
       
  2897 
       
  2898 void CMsvServer::PoliceStopServiceL(const RMessage2& aMsg, TUid aMtm, const char* aContextText)
       
  2899 	{
       
  2900 	// To stop a service, a client is required to be trusted with the capabilities
       
  2901 	// specified by the server MTM.
       
  2902 	TCapabilitySet caps;
       
  2903 	GetMtmRequiredCapabilitiesL(aMtm, caps);
       
  2904 
       
  2905 	// Ok, have the required capabilities - check the client capabilities
       
  2906 	TSecurityInfo clientInfo(aMsg);
       
  2907 
       
  2908 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2909 		{
       
  2910 		// Client missing capabilities - emit diagnostics and leave...
       
  2911 		caps.Remove(clientInfo.iCaps);
       
  2912 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2913 		}
       
  2914 	}
       
  2915 
       
  2916 TBool CMsvServer::ProtectedFolder(TMsvId aFolder) const
       
  2917 	{
       
  2918 	TInt index = iProtectedFolders.Count();
       
  2919 	while( index-- > 0 )
       
  2920 		{
       
  2921 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2922 		if( UnmaskTMsvId(aFolder) == iProtectedFolders[index] )
       
  2923 #else
       
  2924 		if( aFolder == iProtectedFolders[index] )
       
  2925 #endif
       
  2926 			{
       
  2927 			return ETrue;
       
  2928 			}
       
  2929 		}
       
  2930 	return EFalse;
       
  2931 	}
       
  2932 
       
  2933 TBool CMsvServer::ProtectedRemoteServices() const
       
  2934 	{
       
  2935 	return iRemoteServicesProtected;
       
  2936 	}
       
  2937 
       
  2938 void CMsvServer::GetCapsEntryCreateModifyL(const RMessage2& aMsg, TMsvId aFolder, TUid aMtm, TSecureId aOwnerId, TBool aCreateEntry, TBool aLocal, TCapabilitySet& aCaps)
       
  2939 	{
       
  2940 	// Checks what capabilities are required to create/modify an entry under
       
  2941 	// the local for a given type of MTM under the specified folder or under a
       
  2942 	// remote service of given type of MTM.
       
  2943 	//
       
  2944 	// 1. Protected	 - read/write user data.
       
  2945 	// 2. Unprotected   - for creating an entry or modifying an entry that is
       
  2946 	// owned by the client, no capabilities are required, but if modifying an
       
  2947 	// entry not owned by the client then read/write user data is required.
       
  2948 	//
       
  2949 	// Additional capabilities required whether entry under local service or a
       
  2950 	// remote service -
       
  2951 	// 1. Local service - if the entry is under the outbox then the capabilities
       
  2952 	// specified by the MTM are required.
       
  2953 	// 2  Remote service - the capabilities specified by the MTM of the remote
       
  2954 	// entry are required.
       
  2955 	aCaps.SetEmpty();
       
  2956 
       
  2957 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2958 	if( !aLocal || UnmaskTMsvId(aFolder) == KMsvGlobalOutBoxIndexEntryId )
       
  2959 #else
       
  2960 	if( !aLocal || aFolder == KMsvGlobalOutBoxIndexEntryId )
       
  2961 #endif
       
  2962 
       
  2963 		{
       
  2964 		__ASSERT_DEBUG( aMtm != KUidMsvNullEntry, User::Invariant() );
       
  2965 		if( aMtm == KUidMsvNullEntry )
       
  2966 			User::Leave(KErrNotSupported);
       
  2967 
       
  2968 		// Entry being created/modified under the outbox or under a remote service
       
  2969 		// - need the capabilities specified by the MTM.
       
  2970 		GetCapsForMtmL(aMtm, aCaps);
       
  2971 		}
       
  2972 	if( !aLocal && ProtectedRemoteServices() ||
       
  2973 		ProtectedFolder(aFolder) || (!aCreateEntry && aMsg.SecureId()!=aOwnerId) )
       
  2974 		{
       
  2975 		// An entry being created/modified under a protected folder or an entry
       
  2976 		// that is not owned by the client and under an unprotected folder is
       
  2977 		// being modified - need read/write user data capabilities.
       
  2978 		//
       
  2979 		// NOTE - the remote servive is considered protected if the Outbox is
       
  2980 		// protected.
       
  2981 		aCaps.AddCapability(ECapabilityReadUserData);
       
  2982 		aCaps.AddCapability(ECapabilityWriteUserData);
       
  2983 		}
       
  2984 	}
       
  2985 
       
  2986 void CMsvServer::GetCapsForMtmL(TUid aMtm, TCapabilitySet& aCaps)
       
  2987 	{
       
  2988 	// Entry being created/modified under the outbox or under a remote service
       
  2989 	// - need the capabilities specified by the MTM. Check the following
       
  2990 	// 1. MTM is present - if not then by specify the default capabilties of
       
  2991 	// Network Services and Local Services.
       
  2992 	// 2. MTM is not the local service MTM - query the capabilities from the
       
  2993 	// MTM registry.
       
  2994 	// 3. MTM is the local service MTM - no added capabilities required.
       
  2995 	if( aMtm != KUidMsvLocalServiceMtm )
       
  2996 		{
       
  2997 		if( !iServerMtmReg->IsPresent(aMtm) )
       
  2998 			{
       
  2999 			// The MTM is not present - default to Network Services and Local
       
  3000 			// Services.
       
  3001 			aCaps.SetEmpty();
       
  3002 			aCaps.AddCapability(ECapabilityNetworkServices);
       
  3003 			aCaps.AddCapability(ECapabilityLocalServices);
       
  3004 			}
       
  3005 		else
       
  3006 			{
       
  3007 			// The MTM is present and not the local service MTM - query the MTM
       
  3008 			// registry for the required capabilities.
       
  3009 			GetMtmRequiredCapabilitiesL(aMtm, aCaps);
       
  3010 			}
       
  3011 		}
       
  3012 	}
       
  3013 
       
  3014 
       
  3015 
       
  3016 void CMsvServer::NotifyChanged(TMsvServerChangeNotificationType aChangeType, const CMsvEntrySelection& aSelection, TInt aParameter1, TInt aParameter2)
       
  3017 	{
       
  3018 	TMsvPackedChangeNotification package(iChange);
       
  3019 	TInt finish=0;
       
  3020 	do
       
  3021 		{
       
  3022 		TInt start=finish;
       
  3023 		finish = Min(finish + TMsvPackedChangeNotification::KMsvPackedChangeLimit, aSelection.Count());
       
  3024 		package.Pack(aChangeType, aSelection, aParameter1, aParameter2, start, finish-1);
       
  3025 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3026 		iNotification = aChangeType;
       
  3027 #endif
       
  3028 		DoNotify(aChangeType);
       
  3029 		}
       
  3030 	while (finish < aSelection.Count());
       
  3031 	}
       
  3032 
       
  3033 
       
  3034 void CMsvServer::NotifyChanged(TMsvServerChangeNotificationType aChangeType, TMsvId aId, TInt aParameter1, TInt aParameter2)
       
  3035 	{
       
  3036 	TMsvPackedChangeNotification package(iChange);
       
  3037 	package.Pack(aChangeType, aId, aParameter1, aParameter2);
       
  3038 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3039 	iNotification = aChangeType;
       
  3040 #endif
       
  3041 	DoNotify(aChangeType);
       
  3042 	}
       
  3043 
       
  3044 void CMsvServer::NotifyChanged(TMsvServerChangeNotificationType aChangeType, TUid aMtmTypeUid)
       
  3045 	{
       
  3046 	TMsvPackedChangeNotification package(iChange);
       
  3047 	package.Pack(aChangeType, 0, aMtmTypeUid.iUid, 0);
       
  3048 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3049 	iNotification = aChangeType;
       
  3050 #endif
       
  3051 	DoNotify(aChangeType);
       
  3052 	}
       
  3053 
       
  3054 void CMsvServer::QueueNotifyChanged(TMsvServerChangeNotificationType aChangeType)
       
  3055 	{
       
  3056 	TMsvPackedChangeNotification package(iChange);
       
  3057 	package.Pack(aChangeType, 0, 0, 0);
       
  3058 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3059 	iNotification = aChangeType;
       
  3060 #endif
       
  3061 	DoNotify(aChangeType,ETrue);
       
  3062 	}
       
  3063 
       
  3064 void CMsvServer::DoNotify(TMsvServerChangeNotificationType aChangeType,TBool aQueue)
       
  3065 //
       
  3066 // pass the information to each session
       
  3067 //
       
  3068 	{
       
  3069 	iSessionIter.SetToFirst();
       
  3070 	CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3071 	while (ses!=NULL)
       
  3072 		{
       
  3073 #ifndef _NO_SERVER_LOGGING_
       
  3074 		Log(_L("Notifying session, process %S"), &ses->ProcessName());
       
  3075 #endif
       
  3076 		// will only leave if the write to the client fails - so no problem ignoring
       
  3077 		// the leave as the client will have been panic'd anyway
       
  3078 		if(ses->ReceiveEntryEvents() ||
       
  3079 			(aChangeType!=EMsvEntriesCreated &&
       
  3080 			 aChangeType!=EMsvEntriesChanged &&
       
  3081 			 aChangeType!=EMsvEntriesDeleted &&
       
  3082 			 aChangeType!=EMsvEntriesMoved))
       
  3083 			{
       
  3084 			TRAP_IGNORE(ses->NotifyChangedL(iChange, aQueue));
       
  3085 			}
       
  3086 
       
  3087 		ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3088 		}
       
  3089 	}
       
  3090 
       
  3091 TInt CMsvServer::GetEntryName(TMsvId aId, TDes& aFileName, TBool aFolderRequired)
       
  3092 //
       
  3093 // Construct the entry filename
       
  3094 //
       
  3095 	{
       
  3096 	return GetEntryName(*iContext, aId, aFileName, aFolderRequired);
       
  3097 	}
       
  3098 
       
  3099 TInt CMsvServer::GetEntryName(const CMsvIndexContext& aContext, TMsvId aId, TDes& aFileName, TBool aFolderRequired)
       
  3100 //
       
  3101 // Construct the entry filename with the given context
       
  3102 //
       
  3103 	{
       
  3104 	// set up the basic path
       
  3105 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3106 	aContext.MessageFolder(GetDriveId(aId), aFileName);
       
  3107 #else
       
  3108 	aFileName = aContext.MessageFolder();
       
  3109 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3110 
       
  3111 	TInt error=KErrNone;
       
  3112 	TMsvId service=KMsvRootIndexEntryId;
       
  3113 	if (aId!=KMsvRootIndexEntryId)
       
  3114 		{
       
  3115 		error = aContext.IndexAdapter()->OwningService(aId, service);
       
  3116 		}
       
  3117 
       
  3118 	if (error==KErrNone)
       
  3119 		MsvUtils::ConstructEntryName(service, aId, aFileName, (aFolderRequired ? MsvUtils::EFolder : MsvUtils::EStore));
       
  3120 	return error;
       
  3121 	}
       
  3122 
       
  3123 
       
  3124 TInt CMsvServer::GetAndMakeFileDirectory(TMsvId aId, TDes& aDirectory)
       
  3125 //
       
  3126 // Constructs the name of the directory for files associated with the entry id,
       
  3127 // and makes the directory if it doesn't exist
       
  3128 //
       
  3129 	{
       
  3130 	TInt error = GetEntryName(aId, aDirectory, ETrue);
       
  3131 	if (error==KErrNone)
       
  3132 		error = iFs.MkDirAll(aDirectory);
       
  3133 	return (error==KErrAlreadyExists ? KErrNone : error);
       
  3134 	}
       
  3135 
       
  3136 TInt CMsvServer::GetFileDirectoryListing(TMsvId aId, TDes& aDirectory, CDir*& aDir)
       
  3137 //
       
  3138 //
       
  3139 //
       
  3140 	{
       
  3141 	TInt error = GetEntryName(aId, aDirectory, ETrue);
       
  3142 	if (error==KErrNone)
       
  3143 		error =  iFs.GetDir(aDirectory, KEntryAttNormal, ESortNone, aDir);
       
  3144 	return error;
       
  3145 	}
       
  3146 
       
  3147 TInt CMsvServer::AddEntry(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId, TBool aBulk)
       
  3148 	{
       
  3149 
       
  3150 #if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3151 	TDriveUnit defaultDrive(iSystemDrive);
       
  3152 
       
  3153 	// Don't attempt to store the message if the Message Store is being copied
       
  3154 	// from the internal disk to the MMC
       
  3155 	if (iStartupState == EMsvMediaUnavailable)
       
  3156 		{
       
  3157 #ifndef _NO_SERVER_LOGGING_
       
  3158 		Log(_L("CMsvServer::AddEntry - Media is unavailable"));
       
  3159 #endif
       
  3160 
       
  3161 		TInt currentDrive = 0;
       
  3162 		TRAPD(err, currentDrive = MessageServer::CurrentDriveL(iFs));
       
  3163 
       
  3164 		if (err != KErrNone)
       
  3165 			{
       
  3166 			return err;
       
  3167 			}
       
  3168 
       
  3169 		if (currentDrive == defaultDrive)
       
  3170 			{
       
  3171 #ifndef _NO_SERVER_LOGGING_
       
  3172 			Log(_L("Msg store Unavailable, sending KErrNotReady response"));
       
  3173 #endif
       
  3174 			return KErrNotReady;
       
  3175 			}
       
  3176 		}
       
  3177 
       
  3178 	// If we're trying to add something to the Inbox and the disk containing the
       
  3179 	// Message Store is missing, change drive to internal disk
       
  3180 	TInt err = iContext->IndexAdapter()->ErrorState();
       
  3181 	// Assuming the current drive will always be available.
       
  3182 	if (aEntry.iParentId == KMsvGlobalInBoxIndexEntryId && ( err != KErrNone || iStartupState == EMsvMediaUnavailable ) && !iNewContext)
       
  3183 		{
       
  3184 		if(err !=KMsvIndexRestore &&
       
  3185 			err !=KMsvIndexBackup)
       
  3186 			{
       
  3187 #ifndef _NO_SERVER_LOGGING_
       
  3188 			Log(_L("Automatically changing drive to %d"), TInt(defaultDrive));
       
  3189 #endif
       
  3190 			ChangeDrive(TInt(defaultDrive), NULL); // Ignore error?
       
  3191 			}
       
  3192 		}
       
  3193 #endif	  // #if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3194 
       
  3195 	return AddEntry(iContext, aEntry, aOwnerId, aAutoAssignId, aBulk);
       
  3196 	}
       
  3197 
       
  3198 TInt CMsvServer::AddEntry(CMsvIndexContext* const& aContext, TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId, TBool aBulk)
       
  3199 //
       
  3200 // Add a new entry to the Message Store
       
  3201 // Uses the given context
       
  3202 // If aBulk is ETrue,
       
  3203 //	 add entry to bulk selection and update count
       
  3204 //	 based on count, decide whether to commit entry and generate notification
       
  3205 //
       
  3206 	{
       
  3207 	// Return if the message store is not currently available
       
  3208 	TInt err = KErrNone;
       
  3209 	err = aContext->IndexAdapter()->ErrorState();
       
  3210 	if (err != KErrNone)
       
  3211 		return err;
       
  3212 
       
  3213 	// get a unique id for the entry
       
  3214 	if (aAutoAssignId)
       
  3215 		{
       
  3216 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3217 		aEntry.SetId(aContext->IndexAdapter()->NextId(GetDriveId(aEntry.Parent())));
       
  3218 #else
       
  3219 		aEntry.SetId(aContext->IndexAdapter()->NextId());
       
  3220 #endif
       
  3221 		}
       
  3222 
       
  3223 	TInt error = KErrNone;
       
  3224 
       
  3225 	if (aBulk)
       
  3226 		{
       
  3227 		TRAP(error, iBulkCreationSelection->AppendL(aEntry.Id()));
       
  3228 		}
       
  3229 
       
  3230 #ifndef _NO_SERVER_LOGGING_
       
  3231 	Log(_L("Adding entry with id %x"), aEntry.Id());
       
  3232 #endif
       
  3233 
       
  3234 	TFileName fileName;
       
  3235 
       
  3236 	// create the path for a service
       
  3237 	if (aEntry.iType==KUidMsvServiceEntry)
       
  3238 		{
       
  3239 		fileName = aContext->MessageFolder();
       
  3240 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3241 		MsvUtils::ConstructEntryName(UnmaskTMsvId(aEntry.Id()), aEntry.Id(), fileName, MsvUtils::EPath);
       
  3242 #else
       
  3243 		MsvUtils::ConstructEntryName(aEntry.Id(), aEntry.Id(), fileName, MsvUtils::EPath);
       
  3244 #endif
       
  3245 
       
  3246 #ifndef _NO_SERVER_LOGGING_
       
  3247 		Log(_L("Creating path for service %S"), &fileName);
       
  3248 #endif
       
  3249 		error = iFs.MkDir(fileName);
       
  3250 		}
       
  3251 
       
  3252 	// add the entry to the index
       
  3253 	if (error==KErrNone || error==KErrAlreadyExists)
       
  3254 		{
       
  3255 		if (!aBulk)
       
  3256 			{
       
  3257 			error = aContext->IndexAdapter()->AddEntry(aEntry, aOwnerId, EFalse);
       
  3258 			// We may also have a bulk procedure occuring at this time.
       
  3259 			// This call to AddEntry will commit those entries to the index file,
       
  3260 			// so we should let any observers know about the bulk entries now.
       
  3261 			// With the parallel message processing, we will have to forego some of
       
  3262 			// the efficiencies of bulk processing.
       
  3263 			if ((iBulkCreationSelection->Count() != 0) || (iBulkChangeSelection->Count() != 0))
       
  3264 				{
       
  3265 				TRAP(error, NotifyChangedBulkL());
       
  3266 				}
       
  3267 			}
       
  3268 		else
       
  3269 			{
       
  3270 			if (iBulkCreationSelection->Count() == KBulkCommitInterval)
       
  3271 				{
       
  3272 				error = aContext->IndexAdapter()->AddEntry(aEntry, aOwnerId, EFalse);
       
  3273 				// We have done a bulk commit to the index file.
       
  3274 				// Let observers know about the entries
       
  3275 				TRAP(error, NotifyChangedBulkL());
       
  3276 				}
       
  3277 			else
       
  3278 				{
       
  3279 				error = aContext->IndexAdapter()->AddEntryNoCommit(aEntry, aOwnerId, EFalse);
       
  3280 				}
       
  3281 			}
       
  3282 		if (error==KErrNone)
       
  3283 			{
       
  3284 			}
       
  3285 		// Delete the service folder if we created one
       
  3286 		else if ((fileName.Length() > 0) && error!=KErrAlreadyExists)
       
  3287 			iFs.RmDir(fileName);
       
  3288 		}
       
  3289 
       
  3290 	return error;
       
  3291 	}
       
  3292 
       
  3293 
       
  3294 TInt CMsvServer::ChangeEntry(const TMsvEntry& aEntry, TSecureId aOwnerId, TBool aForcedUpdate, TBool aBulk)
       
  3295 //
       
  3296 //
       
  3297 //
       
  3298 	{
       
  3299 #ifndef _NO_SERVER_LOGGING_
       
  3300 	Log(_L("Changing entry with id %x"), aEntry.Id());
       
  3301 #endif
       
  3302 
       
  3303 	TInt error;
       
  3304 	if (!aBulk)
       
  3305 		{
       
  3306 		error = iContext->IndexAdapter()->ChangeEntry(aEntry, aOwnerId, aForcedUpdate);
       
  3307 		// We may also have a bulk procedure occuring at this time.
       
  3308 		// This call to ChangeEntry will commit those entries to the index file,
       
  3309 		// so we should let any observers know about the bulk entries now.
       
  3310 		if ((iBulkCreationSelection->Count() != 0) || (iBulkChangeSelection->Count() != 0))
       
  3311 			{
       
  3312 			TRAP(error, NotifyChangedBulkL());
       
  3313 			}
       
  3314 		}
       
  3315 	else
       
  3316 		{
       
  3317 		TRAP(error, iBulkChangeSelection->AppendL(aEntry.Id()));
       
  3318 		if (error == KErrNone)
       
  3319 			{
       
  3320 			if (iBulkChangeSelection->Count() == KBulkCommitInterval)
       
  3321 				{
       
  3322 				error = iContext->IndexAdapter()->ChangeEntry(aEntry, aOwnerId, aForcedUpdate);
       
  3323 				// We have done a bulk commit to the index file. Let observers know about the entries.
       
  3324 				TRAP(error, NotifyChangedBulkL());
       
  3325 				}
       
  3326 			else
       
  3327 				{
       
  3328 				error = iContext->IndexAdapter()->ChangeEntryNoCommit(aEntry, aOwnerId, aForcedUpdate);
       
  3329 				}
       
  3330 			}
       
  3331 		}
       
  3332 
       
  3333 	return error;
       
  3334 	}
       
  3335 
       
  3336 
       
  3337 
       
  3338 TInt CMsvServer::CheckMtmStatus(TMsvId aServiceId, TBool& aRunning)
       
  3339 //
       
  3340 // Returns
       
  3341 //  KErrNotFound if the mtm is not loaded
       
  3342 //  >=0 if the mtm is loaded and this is the position in the queue array
       
  3343 //  aRunning is true if an operation is currently running
       
  3344 //
       
  3345 	{
       
  3346 	aRunning = EFalse;
       
  3347 	TInt count=iMtmOperationQueueArray.Count();
       
  3348 	while (count--)
       
  3349 		{
       
  3350 		// check if the service has a loaded mtm
       
  3351 		if (iMtmOperationQueueArray.At(count)->ServiceId() == aServiceId)
       
  3352 			{
       
  3353 			aRunning = iMtmOperationQueueArray.At(count)->Count()!=0;
       
  3354 			return count;
       
  3355 			}
       
  3356 		}
       
  3357 	return KErrNotFound;
       
  3358 	}
       
  3359 
       
  3360 #ifdef MSG_SERV_AUTO_CLOSE
       
  3361 void CMsvServer::CheckAndClose()
       
  3362 	{
       
  3363 	// check if any session remaining are just observers - then shut down
       
  3364 
       
  3365 	iSessionIter.SetToFirst();
       
  3366 
       
  3367 	if(iBackup && iBackup->Locked()!=EFalse)
       
  3368 		{
       
  3369 #ifndef _NO_SERVER_LOGGING_
       
  3370 		Log(_L("Not closing sever because we have a backup lock to retake."));
       
  3371 #endif
       
  3372 		}
       
  3373 	else if(iMailinitWaiter->IsActive())
       
  3374 		{
       
  3375 #ifndef _NO_SERVER_LOGGING_
       
  3376 		Log(_L("Not closing sever because we are waiting for mailinit to finish"));
       
  3377 #endif  //_NO_SERVER_LOGGING_
       
  3378 		}
       
  3379 	else if (iSessionIter == NULL)
       
  3380 		{
       
  3381 
       
  3382 		if (iCloseServer)
       
  3383 			{
       
  3384 			CActiveScheduler::Stop();
       
  3385 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3386 			MailinitFinished(KErrNone, iDriveList->CurrentDriveNumber());
       
  3387 #else
       
  3388 			MailinitFinished(KErrNone, (TDriveNumber) (TInt)(iContext->Config().iDrive));
       
  3389 #endif
       
  3390 			}
       
  3391 		else
       
  3392 			{
       
  3393 			iCloseTimer->Cancel();
       
  3394 			iCloseTimer->After(KMsvCloseTime);
       
  3395 			}
       
  3396 		}
       
  3397 	else if (!iCloseServer)
       
  3398 		{
       
  3399 		TBool shouldClose=ETrue;
       
  3400 
       
  3401 		iSessionIter.SetToFirst();
       
  3402 		CMsvServerSession* session = (CMsvServerSession*)&(*iSessionIter++);
       
  3403 		while(session)
       
  3404 			{
       
  3405 			if (!session->IsAnObserver())
       
  3406 				{
       
  3407 				shouldClose=EFalse;
       
  3408 				break;
       
  3409 				}
       
  3410 			session = (CMsvServerSession*)&(*iSessionIter++);
       
  3411 			}
       
  3412 
       
  3413 		if (shouldClose)
       
  3414 			{
       
  3415 #ifndef _NO_SERVER_LOGGING_
       
  3416 			Log(_L("Telling clients to close - CheckAndClose"));
       
  3417 #endif
       
  3418 			NotifyChanged(EMsvCloseSession, KMsvNullIndexEntryId);
       
  3419 			iCloseServer=ETrue;
       
  3420 			}
       
  3421 		}
       
  3422 	}
       
  3423 #endif	  // MSG_SERV_AUTO_CLOSE
       
  3424 
       
  3425 
       
  3426 void CMsvServer::ClosingSession(TInt aSessionId)
       
  3427 //
       
  3428 // Ensures that no mtm are left running when a session is closed
       
  3429 // NOTE Cannot leave - called by CMsvServerSession d'tor
       
  3430 //
       
  3431 	{
       
  3432 	TInt ii = iMtmOperationQueueArray.Count();
       
  3433 	// check each queue
       
  3434 	while (ii--)
       
  3435 		{
       
  3436 		// check if the session used this queue
       
  3437 		CMsvMtmOperationQueue* queue = iMtmOperationQueueArray.At(ii);
       
  3438 		TInt jj = queue->iSessionIdArray.Count();
       
  3439 		while (jj--)
       
  3440 			{
       
  3441 			if (queue != NULL && queue->iSessionIdArray.At(jj)==aSessionId)
       
  3442 				{
       
  3443 				// the session used this queue - so remove the reference to it
       
  3444 				queue->iSessionIdArray.Delete(jj);
       
  3445 
       
  3446 #if defined(_DEBUG)
       
  3447 				// check all session operations have been removed
       
  3448 				TInt kk = queue->Count();
       
  3449 				while (kk--)
       
  3450 					__ASSERT_DEBUG(queue->At(kk)->SessionId()!=aSessionId, PanicServer(EMsvOutstandingOperation));
       
  3451 #endif
       
  3452 				// check if anyone else is using the queue
       
  3453 				if (queue->iSessionIdArray.Count()==0)
       
  3454 					{
       
  3455 					// remove the mtm and queue
       
  3456 					delete queue;
       
  3457 					queue = NULL;
       
  3458 					iMtmOperationQueueArray.Delete(ii);
       
  3459 					}
       
  3460 				}
       
  3461 			}
       
  3462 		}
       
  3463 
       
  3464 	iSessionIter.SetToFirst();
       
  3465 	iSessionIter++;
       
  3466 
       
  3467 	if (iSessionIter == NULL)
       
  3468 		{
       
  3469 		if (iCloseServer)
       
  3470 			{
       
  3471 			CActiveScheduler::Stop();
       
  3472 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3473 			MailinitFinished(KErrNone, iDriveList->CurrentDriveNumber());
       
  3474 #else
       
  3475 			MailinitFinished(KErrNone, (TDriveNumber) (TInt)(iContext->Config().iDrive));
       
  3476 #endif
       
  3477 			}
       
  3478 
       
  3479 #ifdef MSG_SERV_AUTO_CLOSE
       
  3480 		else
       
  3481 			{
       
  3482 			iCloseTimer->Cancel();
       
  3483 			iCloseTimer->After(KMsvCloseTime);
       
  3484 			}
       
  3485 
       
  3486 		}
       
  3487 	else if (!iCloseServer)
       
  3488 		{
       
  3489 		// check if any session remaining are just observers - then shut down
       
  3490 		TBool shouldClose=ETrue;
       
  3491 
       
  3492 		iSessionIter.SetToFirst();
       
  3493 		CMsvServerSession* session = (CMsvServerSession*)&(*iSessionIter++);
       
  3494 		while(session)
       
  3495 			{
       
  3496 			if (!session->IsAnObserver() && session->SessionId() != aSessionId)
       
  3497 				{
       
  3498 				shouldClose=EFalse;
       
  3499 				break;
       
  3500 				}
       
  3501 			session = (CMsvServerSession*)&(*iSessionIter++);
       
  3502 			}
       
  3503 
       
  3504 		if (shouldClose)
       
  3505 			{
       
  3506 #ifndef _NO_SERVER_LOGGING_
       
  3507 			Log(_L("Telling clients to close - Closing session"));
       
  3508 #endif
       
  3509 			NotifyChanged(EMsvCloseSession, KMsvNullIndexEntryId);
       
  3510 			iCloseServer=ETrue;
       
  3511 			}
       
  3512 #endif
       
  3513 
       
  3514 		}
       
  3515 
       
  3516 	}
       
  3517 
       
  3518 
       
  3519 TBool CMsvServer::SessionIdInQueue(CMsvMtmOperationQueue& aQueue, TInt aSessionId) const
       
  3520 //
       
  3521 // Returns true if the session id is already in the queue session id array
       
  3522 //
       
  3523 	{
       
  3524 	TInt count=aQueue.iSessionIdArray.Count();
       
  3525 	while (count--)
       
  3526 		{
       
  3527 		if (aQueue.iSessionIdArray.At(count)==aSessionId)
       
  3528 			return ETrue;
       
  3529 		}
       
  3530 	return EFalse;
       
  3531 	}
       
  3532 
       
  3533 void CMsvServer::QueueOperationL(CMsvMtmOperation& aOperation, TInt aSessionId)
       
  3534 //
       
  3535 // Appends an operation to the correct mtm queue
       
  3536 //
       
  3537 	{
       
  3538 	// append the operation on the right queue
       
  3539 	TInt count=iMtmOperationQueueArray.Count();
       
  3540 	while (count--)
       
  3541 		{
       
  3542 		if (iMtmOperationQueueArray.At(count)->ServiceId() == aOperation.ServiceId())
       
  3543 			{
       
  3544 			AddSessionIdToQueueL(*iMtmOperationQueueArray.At(count), aSessionId);
       
  3545 			iMtmOperationQueueArray.At(count)->AppendL(&aOperation);
       
  3546 			aOperation.SetState(EMsvOperationQueued);
       
  3547 
       
  3548 			}
       
  3549 		}
       
  3550 	__ASSERT_DEBUG(aOperation.State() == EMsvOperationQueued, PanicServer(EMsvOperationQueueNotFound1));
       
  3551 	}
       
  3552 
       
  3553 
       
  3554 void CMsvServer::StartOperationL(CMsvMtmOperation& aOperation, TInt aSessionId, const RMessage2 &aMessage, TBool hasCapability)
       
  3555 //
       
  3556 // Either starts an operation or queues it for later execution
       
  3557 //
       
  3558 	{
       
  3559 	// check the mtm exists
       
  3560 	if (!iServerMtmReg->IsPresent(aOperation.MtmUid()))
       
  3561 		User::Leave(KErrNotFound);
       
  3562 
       
  3563 	// get the status of the service mtm
       
  3564 	TBool opRunning;
       
  3565 	TInt index = CheckMtmStatus(aOperation.ServiceId(), opRunning);
       
  3566 
       
  3567 	// if an operation is already running, queue this one
       
  3568 	if (opRunning)
       
  3569 		{
       
  3570 #if (defined SYMBIAN_USER_PROMPT_SERVICE)        
       
  3571 		aOperation.SetCapability(hasCapability);
       
  3572 #endif
       
  3573 		QueueOperationL(aOperation, aSessionId);
       
  3574 		return;
       
  3575 		}
       
  3576 
       
  3577 	// create the new mtm if required
       
  3578 	CMsvMtmOperationQueue* queue;
       
  3579 	if (index==KErrNotFound)
       
  3580 		{
       
  3581 		queue = new(ELeave) CMsvMtmOperationQueue(aOperation.MtmUid(), aOperation.ServiceId());
       
  3582 		CleanupStack::PushL(queue);
       
  3583 
       
  3584 		// load the mtm and assign to the queue
       
  3585 		queue->iMtm = LoadMtmL(aOperation);
       
  3586 
       
  3587 		// append the operation to the queue
       
  3588 		queue->AppendL(&aOperation);
       
  3589 
       
  3590 		iMtmOperationQueueArray.AppendL(queue);
       
  3591 		CleanupStack::Pop(); // queue
       
  3592 		}
       
  3593 	else
       
  3594 		{
       
  3595 		queue = iMtmOperationQueueArray.At(index);
       
  3596 		queue->AppendL(&aOperation);
       
  3597 		}
       
  3598 	AddSessionIdToQueueL(*queue, aSessionId);
       
  3599 #if (defined SYMBIAN_USER_PROMPT_SERVICE)   
       
  3600 	RThread thread;
       
  3601 	User::LeaveIfError(aMessage.Client(thread));
       
  3602 	TThreadId threadId = thread.Id();
       
  3603 	aOperation.SetThreadId(threadId);
       
  3604 	thread.Close();
       
  3605 #else
       
  3606 	if(aMessage.IsNull()){} // To avoid compiler warnings
       
  3607 #endif
       
  3608 	// start the operation
       
  3609 	aOperation.Start(*queue->iMtm, hasCapability);
       
  3610 	aOperation.SetState(EMsvOperationRunning);
       
  3611 	}
       
  3612 
       
  3613 
       
  3614 
       
  3615 CBaseServerMtm* CMsvServer::LoadMtmL(const CMsvMtmOperation& aOperation)
       
  3616 //
       
  3617 // Returns the server mtm instance required for the operation
       
  3618 //
       
  3619 	{
       
  3620 	CBaseServerMtm* mtm = iServerMtmReg->NewServerMtmL(aOperation.MtmUid(), CMsvServerEntry::NewL(*this, aOperation.ServiceId()));
       
  3621 	return mtm;
       
  3622 	}
       
  3623 
       
  3624 
       
  3625 
       
  3626 #if defined(_DEBUG)
       
  3627 void CMsvServer::OperationCompleted(TMsvId aServiceId, TMsvOp aOpId)
       
  3628 #else
       
  3629 void CMsvServer::OperationCompleted(TMsvId aServiceId, TMsvOp /*aOpId*/)
       
  3630 #endif
       
  3631 //
       
  3632 // An operation has completed, so start the next operation if there is one or remove the Mtm
       
  3633 //
       
  3634 	{
       
  3635 	// find the correct operation queue
       
  3636 	CMsvMtmOperationQueue* queue=NULL;
       
  3637 	TInt count=iMtmOperationQueueArray.Count();
       
  3638 	while (count--)
       
  3639 		{
       
  3640 		if (iMtmOperationQueueArray.At(count)->ServiceId() == aServiceId)
       
  3641 			{
       
  3642 			queue = iMtmOperationQueueArray.At(count);
       
  3643 			break;
       
  3644 			}
       
  3645 		}
       
  3646 	__ASSERT_DEBUG(count>=0, PanicServer(EMsvOperationQueueNotFound2));
       
  3647 
       
  3648 	if ( queue != NULL )
       
  3649 		{
       
  3650 		__ASSERT_DEBUG(queue->At(0)->Id()==aOpId, PanicServer(EMsvWrongOperationCompletion));
       
  3651 
       
  3652 		// mark the operation as completed and remove from the queue
       
  3653 		queue->At(0)->SetState(EMsvOperationCompleted);
       
  3654 		queue->Delete(0);
       
  3655 
       
  3656 		// start the next operation
       
  3657 		StartNextOperation(queue, count);
       
  3658 		}
       
  3659 	}
       
  3660 
       
  3661 TInt CMsvServer::OutstandingOperations()
       
  3662 	{
       
  3663 	TInt count = 0;
       
  3664 	iSessionIter.SetToFirst();
       
  3665 	CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3666 	while (ses!=NULL)
       
  3667 		{
       
  3668 		count += ses->HaveOutstandingOperations();
       
  3669 		ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3670 		}
       
  3671 	return count;
       
  3672 	}
       
  3673 
       
  3674 void CMsvServer::OperationCancelled(const CMsvMtmOperation& aOperation)
       
  3675 //
       
  3676 // An operation has cancelled
       
  3677 //
       
  3678 	{
       
  3679 	const TMsvId aServiceId = aOperation.ServiceId();
       
  3680 
       
  3681 	// find the correct operation queue
       
  3682 	CMsvMtmOperationQueue* queue=NULL;
       
  3683 	TInt qCount=iMtmOperationQueueArray.Count();
       
  3684 	while (qCount--)
       
  3685 		{
       
  3686 		if (iMtmOperationQueueArray.At(qCount)->ServiceId() == aServiceId)
       
  3687 			{
       
  3688 			queue = iMtmOperationQueueArray.At(qCount);
       
  3689 			break;
       
  3690 			}
       
  3691 		}
       
  3692 	__ASSERT_DEBUG(qCount>=0, PanicServer(EMsvOperationQueueNotFound3));
       
  3693 
       
  3694 	// find the correct operation
       
  3695 	if (queue != NULL)
       
  3696 		{
       
  3697 		TInt oCount=queue->Count();
       
  3698 		while (oCount--)
       
  3699 			{
       
  3700 			if (queue->At(oCount) == &aOperation)
       
  3701 				break;
       
  3702 			}
       
  3703 		__ASSERT_DEBUG(oCount>=0, PanicServer(EMsvOperationNotFound));
       
  3704 		__ASSERT_DEBUG(queue->At(oCount)->State()==EMsvOperationQueued, PanicServer(EMsvCancelledNonQueueOp));
       
  3705 		if (oCount>=0)
       
  3706 			queue->Delete(oCount);
       
  3707 		}
       
  3708 	}
       
  3709 
       
  3710 
       
  3711 
       
  3712 void CMsvServer::StartNextOperation(CMsvMtmOperationQueue* aQueue, TInt aQueueIndex)
       
  3713 //
       
  3714 //
       
  3715 //
       
  3716 	{
       
  3717 	// if there are no more operations
       
  3718 	if (aQueue->Count()==0)
       
  3719 		{
       
  3720 		if (!aQueue->iMtm->CommandExpected())
       
  3721 			{
       
  3722 			// the mtm is no longer needed
       
  3723 			delete iMtmOperationQueueArray.At(aQueueIndex);
       
  3724 			iMtmOperationQueueArray.Delete(aQueueIndex);
       
  3725 			}
       
  3726 		return;
       
  3727 		}
       
  3728 
       
  3729 
       
  3730 	// if the Mtm cannot accept multiple commands, create a new one
       
  3731 	if (!aQueue->iMtm->CommandExpected())
       
  3732 		{
       
  3733 		delete aQueue->iMtm;
       
  3734 		aQueue->iMtm=NULL;
       
  3735 		TRAPD(leave, {aQueue->iMtm = LoadMtmL(*aQueue->At(0));});
       
  3736 		if (leave)
       
  3737 			{
       
  3738 			// fail all queued operations
       
  3739 			TInt count=aQueue->Count();
       
  3740 			while (count--)
       
  3741 				{
       
  3742 				aQueue->At(count)->Failed(leave);
       
  3743 				aQueue->Delete(count);
       
  3744 				}
       
  3745 			// delete the mtm queue
       
  3746 			delete iMtmOperationQueueArray.At(aQueueIndex);
       
  3747 			iMtmOperationQueueArray.Delete(aQueueIndex);
       
  3748 			return;
       
  3749 			}
       
  3750 		}
       
  3751 	
       
  3752 #if (defined SYMBIAN_USER_PROMPT_SERVICE)
       
  3753 	aQueue->At(0)->Start(*aQueue->iMtm, aQueue->At(0)->Capability());
       
  3754 #else
       
  3755 	aQueue->At(0)->Start(*aQueue->iMtm, EFalse);
       
  3756 #endif
       
  3757 	aQueue->At(0)->SetState(EMsvOperationRunning);
       
  3758 	}
       
  3759 
       
  3760 
       
  3761 TInt CMsvServer::FillRegisteredMtmDllArray(TUid aMtmDllTypeUid,CRegisteredMtmDllArray& aRegisteredMtmDllArray)
       
  3762 	{
       
  3763 	return iMtmRegControl->FillRegisteredMtmDllArray(aMtmDllTypeUid,aRegisteredMtmDllArray);
       
  3764 	}
       
  3765 
       
  3766 
       
  3767 TInt CMsvServer::InstallMtmGroup(const TDesC& aFullName,TUid& aMtmTypeUid)
       
  3768 	{
       
  3769 	TInt error=iMtmRegControl->InstallMtmGroup(aFullName,aMtmTypeUid);
       
  3770 	return error;
       
  3771 	}
       
  3772 
       
  3773 
       
  3774 TInt CMsvServer::DeInstallMtmGroup(const TDesC& aFullName,TUid& aMtmTypeUid)
       
  3775 	{
       
  3776 	TInt error=iMtmRegControl->FullNameToMtmTypeUid(aFullName,aMtmTypeUid);
       
  3777 	if (error==KErrNone)
       
  3778 		{
       
  3779 		TBool isinuse=iMtmRegControl->IsInUse(aMtmTypeUid);
       
  3780 		if (!isinuse)
       
  3781 			{
       
  3782 			iSessionIter.SetToFirst();
       
  3783 			CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3784 			while ((ses!=NULL) && !isinuse)
       
  3785 				{
       
  3786 				isinuse=ses->IsInUse(aMtmTypeUid);
       
  3787 				ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3788 				}
       
  3789 			}
       
  3790 		if (isinuse)
       
  3791 			error=KErrInUse;
       
  3792 		}
       
  3793 	if (error==KErrNone)
       
  3794 		error=iMtmRegControl->DeInstallMtmGroup(aMtmTypeUid);
       
  3795 	return error;
       
  3796 	}
       
  3797 
       
  3798 
       
  3799 CMtmGroupData* CMsvServer::GetMtmGroupDataL(TUid aMtmTypeUid) const
       
  3800 	{
       
  3801 	return iMtmRegControl->GetMtmGroupDataL(aMtmTypeUid);
       
  3802 	}
       
  3803 
       
  3804 
       
  3805 void CMsvServer::GetMtmRequiredCapabilitiesL(TUid aMtmTypeUid, TCapabilitySet& aCaps) const
       
  3806 	{
       
  3807 	aCaps=iMtmRegControl->GetMtmGroupDataReferenceL(aMtmTypeUid).GetMtmRequiredCapabilities();
       
  3808 	}
       
  3809 
       
  3810 
       
  3811 void CMsvServer::StopServiceL(const RMessage2& aMessage)
       
  3812 //
       
  3813 // Stops a service by cancelling all operations and deleting the server MTM
       
  3814 //
       
  3815 	{
       
  3816 	TMsvId serviceId = aMessage.Int0();
       
  3817 	TBool active;
       
  3818 	TInt index = CheckMtmStatus(serviceId, active);
       
  3819 
       
  3820 	// service MTM is not loaded
       
  3821 	if (index==KErrNotFound)
       
  3822 		{
       
  3823 		aMessage.Complete(KErrNotFound);
       
  3824 		return;
       
  3825 		}
       
  3826 
       
  3827 	// The service MTM is loaded - police if the client can stop it.
       
  3828 	PoliceStopServiceL(aMessage, iMtmOperationQueueArray.At(index)->MtmUid(), __PLATSEC_DIAGNOSTIC_STRING("Checked by CMsvServer::StopService"));
       
  3829 
       
  3830 	// get all sessions to cancel/stop the operations
       
  3831 	iSessionIter.SetToFirst();
       
  3832 	CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3833 	while (ses!=NULL)
       
  3834 		{
       
  3835 		ses->StopOperations(serviceId);
       
  3836 		ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3837 		}
       
  3838 
       
  3839 	// check if the server MTM has been persisted
       
  3840 	index = CheckMtmStatus(serviceId, active);
       
  3841 	// remove the queue - irrespective of request of the Server MTM
       
  3842 	if (index!=KErrNotFound)
       
  3843 		{
       
  3844 		delete iMtmOperationQueueArray.At(index);
       
  3845 		iMtmOperationQueueArray.Delete(index);
       
  3846 		}
       
  3847 	aMessage.Complete(KErrNone);
       
  3848 	}
       
  3849 
       
  3850 
       
  3851 
       
  3852 void CMsvServer::ServiceActive(const RMessage2& aMessage)
       
  3853 //
       
  3854 // Completes ETrue if the server MTM is running an operation
       
  3855 //
       
  3856 	{
       
  3857 	TMsvId serviceId = aMessage.Int0();
       
  3858 	TBool active;
       
  3859 	CheckMtmStatus(serviceId, active); // error ignored as "active" is always set correctly
       
  3860 	aMessage.Complete(active);
       
  3861 	}
       
  3862 
       
  3863 
       
  3864 
       
  3865 const TDesC8& CMsvServer::ServiceProgressL(TMsvId aServcieId)
       
  3866 //
       
  3867 // Returns the progress from the server MTM
       
  3868 //
       
  3869 	{
       
  3870 	TBool active;
       
  3871 	TInt index = CheckMtmStatus(aServcieId, active);
       
  3872 
       
  3873 	// service MTM is not loaded
       
  3874 	if (index==KErrNotFound)
       
  3875 		User::Leave(KErrNotFound);
       
  3876 
       
  3877 	// get the progress from the server MTM
       
  3878 	CMsvMtmOperationQueue* queue = iMtmOperationQueueArray.At(index);
       
  3879 	return queue->iMtm->Progress();
       
  3880 	}
       
  3881 
       
  3882 
       
  3883 void CMsvServer::AttemptDelayedUpdating()
       
  3884 //
       
  3885 //
       
  3886 //
       
  3887 	{
       
  3888 	if (iContext)
       
  3889 		{
       
  3890 		if(iContext->Initialized()==EFalse)
       
  3891 			{
       
  3892 			iContext->Initialized(ETrue);
       
  3893 			TRAP_IGNORE({iContext->LocalizeStandardFoldersL();
       
  3894 							SuspendSendingMessagesL();});
       
  3895 			}
       
  3896 
       
  3897 		if (iContext->Remove().Count())
       
  3898 			RemoveEntry(KMsvNullIndexEntryId);
       
  3899 
       
  3900 		if (iContext->Update().Count() && !iDelayTimer->IsActive())
       
  3901 			iDelayTimer->After(KMsvDelayTime);
       
  3902 		}
       
  3903 	}
       
  3904 
       
  3905 
       
  3906 
       
  3907 
       
  3908 // this cleans up messages left sending when the machine was
       
  3909 // rebooted, as they would otherwise be displayed to the user
       
  3910 // as sending when they aren't
       
  3911 // A better fix would be to allow the server mtms to clean up
       
  3912 // on startup, then they could attempt to continue sending the
       
  3913 // message.
       
  3914 // This also only copes with mtms that either use the KMsvSendStateSending and KMsvSendStateWaiting
       
  3915 // or the fax mtm because I know about those.
       
  3916 
       
  3917 // copied from fxut.h included so that we can set things with fax sending states
       
  3918 // to suspended on message server start
       
  3919 // horrible but we don't want to have to have fax available to build the message
       
  3920 // server.
       
  3921 enum TFaxSendingState
       
  3922 	{
       
  3923 	EFaxSendingStateCalling = (KMsvSendStateLast + 1),
       
  3924 		EFaxSendingStateNegotiating,
       
  3925 		EFaxSendingStatePreparing
       
  3926 	};
       
  3927 // can't find a header that defines this (it is defined in FXSENDOP.CPP
       
  3928 // and FAXC.CPP but I don't want to move it into a header now.
       
  3929 const TUid KUidMsgTypeFax = {0x1000102B};
       
  3930 
       
  3931 void CMsvServer::SuspendSendingMessagesL()
       
  3932 	{
       
  3933 	CMsvEntrySelection *selection=new(ELeave)CMsvEntrySelection;
       
  3934 	CleanupStack::PushL(selection);
       
  3935 	CMsvEntryFilter *filter=CMsvEntryFilter::NewLC();
       
  3936 	
       
  3937 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3938 		User::LeaveIfError(iContext->IndexAdapter()->GetChildrenIdAll(KMsvGlobalOutBoxIndexEntryId,*filter,*selection));
       
  3939 #else
       
  3940 		User::LeaveIfError(iContext->IndexAdapter()->GetChildrenId(KMsvGlobalOutBoxIndexEntryId,*filter,*selection));
       
  3941 #endif
       
  3942 
       
  3943 	TInt count=selection->Count();
       
  3944 	while(count--)
       
  3945 		{
       
  3946 		TMsvEntry *entry;
       
  3947 		TInt err = KErrNone;
       
  3948 		err = iContext->IndexAdapter()->GetEntry(selection->At(count),entry);
       
  3949 		if(err == KErrNone)
       
  3950 			{
       
  3951 			const TUint sendingState=entry->SendingState();
       
  3952 
       
  3953 			if(sendingState==KMsvSendStateSending ||
       
  3954 			   sendingState==KMsvSendStateWaiting ||
       
  3955 				(entry->iMtm==KUidMsgTypeFax && (sendingState== EFaxSendingStateCalling ||
       
  3956 												 sendingState== EFaxSendingStateNegotiating ||
       
  3957 												 sendingState== EFaxSendingStatePreparing)))
       
  3958 				{
       
  3959 				entry->SetSendingState(KMsvSendStateSuspended);
       
  3960 				// ignore error as we can't report it and want to try fixing
       
  3961 				// the next entry in the list.
       
  3962 				iContext->IndexAdapter()->ChangeEntry(*entry, KMsvServerId, EFalse);
       
  3963 				}
       
  3964 			}
       
  3965 		}
       
  3966 	CleanupStack::PopAndDestroy(2,selection); //filter, selection
       
  3967 	}
       
  3968 
       
  3969 void CMsvServer::RemoveEntry(TMsvId aId)
       
  3970 //
       
  3971 // Removes the removed entries from the index. Client were not interested in result.
       
  3972 //
       
  3973 	{
       
  3974 #ifndef _NO_SERVER_LOGGING_
       
  3975 	TRAPD(leave, DoRemoveEntriesL(aId));
       
  3976 	Log(_L("Remove entry %x, error %d, list size %d"), aId, leave, iContext->Remove().Count());
       
  3977 #else
       
  3978 	TRAP_IGNORE(DoRemoveEntriesL(aId));
       
  3979 #endif
       
  3980 
       
  3981 	// start the timer if entries are stil requiring removal and the timer isn't running
       
  3982 	if (iContext->Remove().Count() && !iDelayTimer->IsActive())
       
  3983 		iDelayTimer->After(KMsvDelayTime);
       
  3984 	}
       
  3985 
       
  3986 void CMsvServer::DoRemoveEntriesL(TMsvId aId)
       
  3987 //
       
  3988 // Deletes the removed entries from the index. Client were not interested in result.
       
  3989 //
       
  3990 	{
       
  3991 	if (aId!=KMsvNullIndexEntryId)
       
  3992 		{
       
  3993 		iContext->Remove().AppendL(aId);
       
  3994 		iContext->Remove().SetReserveL(iContext->Remove().Count()+1);
       
  3995 		}
       
  3996 	else if (iContext->Remove().Count()==0)
       
  3997 		return;
       
  3998 
       
  3999 	CMsvEntrySelection* deletedSelection = new(ELeave) CMsvEntrySelection;
       
  4000 	CleanupStack::PushL(deletedSelection);
       
  4001 	CMsvEntrySelection* movedSelection = new(ELeave) CMsvEntrySelection;
       
  4002 	CleanupStack::PushL(movedSelection);
       
  4003 	CMsvDelete* deleteEntry = CMsvDelete::NewL(*this);
       
  4004 	CleanupStack::PushL(deleteEntry);
       
  4005 
       
  4006 	TInt count=iContext->Remove().Count();
       
  4007 	while (count--)
       
  4008 		{
       
  4009 		// find the parent
       
  4010 		TMsvEntry* entry;
       
  4011 		TInt error = KErrNone;
       
  4012 		error = iContext->IndexAdapter()->GetEntry(iContext->Remove().At(count), entry);
       
  4013 		if (error)
       
  4014 			continue;
       
  4015 
       
  4016 		// delete the entry
       
  4017 		TMsvId parent = entry->Parent();
       
  4018 
       
  4019 		// Note: It should be possible to get rid of this trap - but this is safer for now
       
  4020 		TRAP(error, deleteEntry->StartL(entry->Id(), *deletedSelection, *movedSelection));
       
  4021 		if (error == KErrNone)
       
  4022 			{
       
  4023 			// notify client of a deletion
       
  4024 			iContext->Remove().Delete(count);
       
  4025 			if (deletedSelection->Count())
       
  4026 				NotifyChanged(EMsvEntriesDeleted, *deletedSelection, parent);
       
  4027 			if (movedSelection->Count())
       
  4028 				{
       
  4029 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4030 				NotifyChanged(EMsvEntriesMoved, *movedSelection, MaskTMsvId(GetDriveId(aId), KMsvDeletedEntryFolderEntryId), parent);
       
  4031 #else
       
  4032 				NotifyChanged(EMsvEntriesMoved, *movedSelection, KMsvDeletedEntryFolderEntryId, parent);
       
  4033 #endif
       
  4034 				}
       
  4035 			}
       
  4036 
       
  4037 		deletedSelection->Reset();
       
  4038 		movedSelection->Reset();
       
  4039 		}
       
  4040 
       
  4041 	CleanupStack::PopAndDestroy(3); // moveSelection, deletedSelection, deleteentry
       
  4042 	}
       
  4043 
       
  4044 
       
  4045 void CMsvServer::CloseServer(const RMessage2& aMessage)
       
  4046 //
       
  4047 // Tells alls sessions to close, and when all are closed the server is shut down immediately
       
  4048 //
       
  4049 	{
       
  4050 #ifndef _NO_SERVER_LOGGING_
       
  4051 	Log(_L("Telling clients to close - close server function"));
       
  4052 #endif
       
  4053 	aMessage.Complete(KErrNone);
       
  4054 	NotifyChanged(EMsvCloseSession, KMsvNullIndexEntryId);
       
  4055 	iCloseServer=ETrue;
       
  4056 	}
       
  4057 
       
  4058 
       
  4059 TInt CMsvServer::CheckEntries(const CMsvEntrySelection& aEntries, TInt aStartIndex, TInt aEndIndex)
       
  4060 //
       
  4061 // Checks that all entries in the selection can be deleted, copied, moved etc
       
  4062 //
       
  4063 	{
       
  4064 	for (TInt index=aStartIndex; index<=aEndIndex; index++)
       
  4065 		{
       
  4066 		TMsvId id = aEntries.At(index);
       
  4067 		TBool locked;
       
  4068 		TInt error = KErrNone;
       
  4069 		error = iContext->IndexAdapter()->IsEntryOrStoreLocked(id, locked);
       
  4070 		if (error)
       
  4071 			return error;
       
  4072 		if (locked)
       
  4073 			return KErrAccessDenied;
       
  4074 
       
  4075 		// get the entry
       
  4076 		TMsvEntry* entry;
       
  4077 		iContext->IndexAdapter()->GetEntry(id, entry); // error ignored, as will not fail
       
  4078 		// check the store
       
  4079 		TFileName filename;
       
  4080 		GetEntryName(id, filename, EFalse);
       
  4081 		TBool open;
       
  4082 		error = iFs.IsFileOpen(filename, open);
       
  4083 		if (error)
       
  4084 			{
       
  4085 			if (error!=KErrNotFound && error!=KErrPathNotFound)
       
  4086 				return error;
       
  4087 			}
       
  4088 		else if (open)
       
  4089 			return KErrInUse;
       
  4090 
       
  4091 		// check any files
       
  4092 		CDir* dir;
       
  4093 		error = GetFileDirectoryListing(id, filename, dir);
       
  4094 		if (error == KErrNone)
       
  4095 			{
       
  4096 			error = iFs.SetSessionPath(filename);
       
  4097 			if (error==KErrNone)
       
  4098 				{
       
  4099 				TInt fCount = dir->Count();
       
  4100 				while (fCount--)
       
  4101 					{
       
  4102 					TBool open;
       
  4103 					error = iFs.IsFileOpen((*dir)[fCount].iName, open);
       
  4104 					if (error)
       
  4105 						{
       
  4106 						if (error!=KErrNotFound && error!=KErrPathNotFound)
       
  4107 							{
       
  4108 							delete dir;
       
  4109 							return error;
       
  4110 							}
       
  4111 						}
       
  4112 					else if (open)
       
  4113 						{
       
  4114 						delete dir;
       
  4115 						return KErrInUse;
       
  4116 						}
       
  4117 					}
       
  4118 				}
       
  4119 			delete dir;
       
  4120 			if (error)
       
  4121 				return error;
       
  4122 			}
       
  4123 		else if (error != KErrPathNotFound)
       
  4124 			return error;
       
  4125 		}
       
  4126 	return KErrNone;
       
  4127 	}
       
  4128 
       
  4129 
       
  4130 #ifndef _NO_SERVER_LOGGING_
       
  4131 void CMsvServer::CreateLogL()
       
  4132 	{
       
  4133 	// Connect to flogger
       
  4134 	if (iLog.Connect() == KErrNone)
       
  4135 		{
       
  4136 		iLog.CreateLog(_L("msgs"), _L("server.txt"), EFileLoggingModeOverwrite);
       
  4137 		iLog.SetDateAndTime(EFalse, ETrue);
       
  4138 
       
  4139 		TTime date;
       
  4140 		date.UniversalTime();
       
  4141 
       
  4142 		TBuf<32> dateString;
       
  4143 		date.FormatL(dateString,(_L("%D%M%Y%/0%1%/1%2%/2%3%/3")));
       
  4144 
       
  4145 		TPtrC ver(MessageServer::Version().Name());
       
  4146 		Log(_L("Started message server, date %S, version %S"), &dateString, &ver);
       
  4147 		}
       
  4148 	}
       
  4149 
       
  4150 void CMsvServer::Log(TRefByValue<const TDesC> aFmt, ...)
       
  4151 	{
       
  4152 	if (!iLog.LogValid())
       
  4153 		return;
       
  4154 
       
  4155 	VA_LIST list;
       
  4156 	VA_START(list, aFmt);
       
  4157 
       
  4158 	TBuf<256> buf;
       
  4159 	buf.FormatList(aFmt, list);
       
  4160 
       
  4161 	// Write to log
       
  4162 	iLog.Write(buf);
       
  4163 
       
  4164 #ifndef _NO_SERVER_LOGGING_SERIAL_
       
  4165 	// Write to serial
       
  4166 	_LIT(KFormatSerial, "MSGS: %S");
       
  4167 	RDebug::Print(KFormatSerial, &buf);
       
  4168 #endif
       
  4169 	}
       
  4170 #endif	  // #ifndef _NO_SERVER_LOGGING_
       
  4171 
       
  4172 
       
  4173 
       
  4174 void CMsvServer::SetFailure(TMsvFailure aType, TInt aArg1, TInt aArg2, TInt)
       
  4175 	{
       
  4176 	switch (aType)
       
  4177 		{
       
  4178 		case EHeapFailure:
       
  4179 			User::__DbgSetAllocFail(RHeap::EUser, (RHeap::TAllocFail)aArg1, aArg2);
       
  4180 			break;
       
  4181 		case EDiskFailure:
       
  4182 #if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4183 			iNotify->SetDiskMissing(aArg1);
       
  4184 			iNotify->SetWrongId(aArg2);
       
  4185 #endif
       
  4186 			break;
       
  4187 		}
       
  4188 	}
       
  4189 
       
  4190 
       
  4191 
       
  4192 
       
  4193 void CMsvServer::SetStartupState(TMsvServerChangeNotificationType aState)
       
  4194 	{
       
  4195 	iStartupState=aState;
       
  4196 	}
       
  4197 
       
  4198 const TDriveUnit &CMsvServer::Drive() const
       
  4199 	{
       
  4200 	return(iIndexDrive);
       
  4201 	}
       
  4202 
       
  4203 
       
  4204 
       
  4205 void CMsvServer::MailinitFinished(TInt aError, TDriveNumber aDriveNum)
       
  4206 	{
       
  4207 	// if mailinit exited sucessfully try and delete the
       
  4208 	// flag file.
       
  4209 	if(aError==KErrNone)
       
  4210 		{
       
  4211 		// remove the mailinit flag file, ignore errors it will just mean
       
  4212 		// we run mailinit next time the server starts and we require that
       
  4213 		// mailinit.exe handles this gracefully.
       
  4214 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4215 		if(iFs.SetSessionToPrivate(aDriveNum) == KErrNone)
       
  4216 #else
       
  4217 		// Just to ignore the warning.
       
  4218 		aDriveNum = aDriveNum;
       
  4219 		if(iFs.SetSessionToPrivate(iContext->Config().iDrive) == KErrNone)
       
  4220 #endif	  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4221 
       
  4222 			{
       
  4223 			iFs.Delete(KMsvStoreInitFileName);
       
  4224 			}
       
  4225 		}
       
  4226 #ifdef MSG_SERV_AUTO_CLOSE
       
  4227 	// we may have delayed shutdown to allow mailinit to finish, so
       
  4228 	// let the server shutdown if it wants to.
       
  4229 	CheckAndClose();
       
  4230 #endif
       
  4231 	}
       
  4232 
       
  4233 
       
  4234 TMsvServerStoreManager& CMsvServer::ServerStoreManager()
       
  4235 	{
       
  4236 	return iServerStoreManager;
       
  4237 	}
       
  4238 
       
  4239 void CMsvServer::GetNonOperationMtmDataL(TMsvId aServiceId, TNonOperationMtmDataType aMtmDataType, TPtrC8& aResultBuffer)
       
  4240 	{
       
  4241 	TBool active;
       
  4242 	TInt index = CheckMtmStatus(aServiceId, active);
       
  4243 
       
  4244 	if (index == KErrNotFound)
       
  4245 		{
       
  4246 		User::Leave(KErrNotFound);
       
  4247 		}
       
  4248 
       
  4249 	User::LeaveIfError(iMtmOperationQueueArray.At(index)->iMtm->GetNonOperationMtmData(aMtmDataType, aResultBuffer));
       
  4250 	}
       
  4251 
       
  4252 
       
  4253 /**
       
  4254 Checks client capabilty for readuserdata for performing search sort operation
       
  4255 */
       
  4256 void CMsvServer::PoliceSearchSortQueryReadRequestL(const RMessage2& aMsg, const char* aContextText)
       
  4257 	{
       
  4258 	// The client can read the entry under following circumstances.
       
  4259 	// 1. The client has Read User Data capability.
       
  4260 	// 2. The client does not have Read User Data but owns the entry.
       
  4261 
       
  4262 	// First check if the client is trusted with Read User Data.
       
  4263 	if( !aMsg.HasCapability(ECapabilityReadUserData) )
       
  4264 		{
       
  4265 		// Client not trusted with Read User data 
       
  4266 			{
       
  4267 			// Client missing capabilities - emit diagnostics and leave...
       
  4268 			User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, ECapabilityReadUserData, aContextText));
       
  4269 			}
       
  4270 		}
       
  4271 	}
       
  4272 
       
  4273 
       
  4274 //**********************************
       
  4275 // CMsvTimer
       
  4276 //**********************************
       
  4277 
       
  4278 CMsvTimer::CMsvTimer(CMsvServer& aServer, TBool aCloseServer)
       
  4279 : CTimer(EPriorityLow), iServer(aServer), iCloseServer(aCloseServer)
       
  4280 	{}
       
  4281 
       
  4282 void CMsvTimer::RunL()
       
  4283 	{
       
  4284 	iServer.AttemptDelayedUpdating();
       
  4285 	if (iCloseServer)
       
  4286 		{
       
  4287 		CActiveScheduler::Stop();
       
  4288 		}
       
  4289 	}
       
  4290 
       
  4291 CMsvTimer* CMsvTimer::NewL(CMsvServer& aServer, TBool aCloseServer)
       
  4292 	{
       
  4293 	CMsvTimer* self = new(ELeave) CMsvTimer(aServer, aCloseServer);
       
  4294 	CleanupStack::PushL(self);
       
  4295 	self->ConstructL(); // CTimer
       
  4296 	CActiveScheduler::Add(self);
       
  4297 	CleanupStack::Pop();
       
  4298 	return self;
       
  4299 	}
       
  4300 
       
  4301 
       
  4302 //**********************************
       
  4303 // MessageServer
       
  4304 //**********************************
       
  4305 
       
  4306 EXPORT_C TVersion MessageServer::Version()
       
  4307 /** Returns the Message Server version number.
       
  4308 
       
  4309 @return Message server version number */
       
  4310 	{
       
  4311 	return TVersion(KMsvServerMajorVersionNumber,KMsvServerMinorVersionNumber,KMsvServerBuildVersionNumber);
       
  4312 	}
       
  4313 
       
  4314 
       
  4315 
       
  4316 
       
  4317 EXPORT_C TMsvId MessageServer::NullUidValue()
       
  4318 /** Returns the predefined message entry ID null value.
       
  4319 
       
  4320 @return Message entry ID null value */
       
  4321 	{
       
  4322 	return KMsvNullIndexEntryId;
       
  4323 	}
       
  4324 
       
  4325 
       
  4326 
       
  4327 
       
  4328 EXPORT_C TBool MessageServer::DriveContainsStore(RFs& aFs, TInt aDrive)
       
  4329 /** Checks if the specified drive has a Message Server index on it.
       
  4330 
       
  4331 @capability AllFiles If not within the message server process
       
  4332 @capability None If within the message server process
       
  4333 
       
  4334 @param aFs File server session
       
  4335 @param aDrive Drive to check, specified by a TDriveNumber value
       
  4336 @return True if aDrive has a Message Server index, otherwise false
       
  4337 @see TDriveNumber */
       
  4338 	{
       
  4339 	TParse parse1, parse2;
       
  4340 	TDriveUnit driveUnit(aDrive);
       
  4341 	TPtrC driveName(driveUnit.Name());
       
  4342 	
       
  4343 	// Check the existence of index file.
       
  4344 	parse1.Set(KMsvDefaultIndexFile,  &driveName, NULL);
       
  4345 	parse2.Set(KMsvDefaultIndexFile2, &driveName, NULL);
       
  4346 	TBool isMessageStoreExists =  BaflUtils::FileExists(aFs, parse1.FullName())
       
  4347 							  ||  BaflUtils::FileExists(aFs, parse2.FullName());
       
  4348 	
       
  4349 	// If index file is not present,
       
  4350 	// check the existence of index DB.
       
  4351 	if(!isMessageStoreExists)
       
  4352 		{
       
  4353 		parse1.Set(KMsvDbFile, &driveName, NULL);
       
  4354 		TFileName dBFile = parse1.FullName();   
       
  4355 		RSqlDatabase db;
       
  4356 		TRAPD(err, db.OpenL(dBFile));
       
  4357 		isMessageStoreExists = (KErrNone == err)? ETrue: EFalse;
       
  4358 		db.Close();
       
  4359 		}
       
  4360 	
       
  4361 	return isMessageStoreExists;
       
  4362 	}
       
  4363 	
       
  4364 	
       
  4365 
       
  4366 
       
  4367 EXPORT_C TInt MessageServer::CurrentDriveL(RFs& aFs)
       
  4368 /** Returns the drive that the Message Server is using to store messages.
       
  4369 
       
  4370 @capability AllFiles If not within the message server process
       
  4371 @capability None If within the message server process
       
  4372 @param aFs File server session
       
  4373 @return Drive used, specified by a TDriveNumber value
       
  4374 @see TDriveNumber */
       
  4375 	{
       
  4376 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4377 	aFs = aFs;		  // This avoids warning.
       
  4378 	
       
  4379 	// Get the current drive info from cenrep.
       
  4380 	CRepository* repository = CRepository::NewL(KUidConfigFile);
       
  4381 	TInt driveNum;
       
  4382 	TInt err = repository->Get(KCenRepCurrentDriveKey, driveNum);
       
  4383 	delete repository;
       
  4384 	
       
  4385 	if( (err != KErrNone) || (driveNum > EDriveZ) )
       
  4386 		{
       
  4387 		User::Leave(KErrNotFound);  
       
  4388 		}
       
  4389 	return driveNum;
       
  4390 
       
  4391 #else
       
  4392 	TMsvConfig config;
       
  4393 	CMsvServer::CurrentConfigL(aFs, config);
       
  4394 	return config.iDrive;
       
  4395 #endif	  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4396 	}
       
  4397 	
       
  4398 	
       
  4399 	
       
  4400 
       
  4401 /** Checks to see if the currently selected drive contains the correct mail store.
       
  4402 
       
  4403 If the message store is present on an external drive, we have to check if the same drive is
       
  4404 mounted or not before storing the mail.
       
  4405 
       
  4406 @return ETrue if the same drive is mounted. otherwise returns EFalse
       
  4407 @capability None
       
  4408 */
       
  4409 EXPORT_C TBool MessageServer::IsMessageStoreDrivePresentL(RFs& aFs)
       
  4410 	{   
       
  4411 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4412 	aFs = aFs;
       
  4413 	return ETrue;   
       
  4414 #else
       
  4415 	TUint uniqueId = 0;
       
  4416 	TMsvConfig config;
       
  4417 	CMsvServer::CurrentConfigL(aFs, config);
       
  4418 	//Check whether the drive and uid mentioned in the msgs.ini are mounted
       
  4419 	TVolumeInfo volumeInfo;
       
  4420 	uniqueId = config.iUniqueID;
       
  4421 
       
  4422 	User::LeaveIfError(aFs.Volume(volumeInfo, config.iDrive.operator TInt()));
       
  4423 	//Check whether the uid stored in msgs.ini and mounted drive's uid are same
       
  4424 	if(volumeInfo.iUniqueID == uniqueId)
       
  4425 		{
       
  4426 		return ETrue;
       
  4427 		}
       
  4428 	return EFalse;
       
  4429 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4430 	}
       
  4431 
       
  4432 
       
  4433 
       
  4434 
       
  4435 
       
  4436 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4437 /**
       
  4438  * IsMessageStoreSupported()
       
  4439  *
       
  4440  * @param TDriveNumber: The drive number of the drive.
       
  4441  * @return TBool: ETrue: If the drive has a valid version of message store.
       
  4442  *				EFalse: Otherwise.
       
  4443  */
       
  4444 EXPORT_C TBool MessageServer::IsMessageStoreSupported(TDriveNumber aDrive)
       
  4445 	{
       
  4446 	TParse parse;
       
  4447 	TPtrC driveName(TDriveUnit(aDrive).Name());
       
  4448 	
       
  4449 	// Check if the message index database 
       
  4450 	// exists and it has a valid version.
       
  4451 
       
  4452 	parse.Set(KMsvDbFile, &driveName, NULL);
       
  4453 	TFileName dBFile = parse.FullName();	
       
  4454 	RSqlDatabase db;
       
  4455 	TRAPD(err, db.OpenL(dBFile));
       
  4456 	if(KErrNone == err)
       
  4457 		{
       
  4458 		TInt version = 0;
       
  4459 		TSqlScalarFullSelectQuery query(db);
       
  4460 		_LIT8(KSelectVersionQuery, "SELECT version FROM VersionTable;");
       
  4461 		
       
  4462 		TRAP(err, version = query.SelectIntL(KSelectVersionQuery));	 
       
  4463 		if( (KErrNone == err) && (version == KCurrentDatabaseVersion) )
       
  4464 			{
       
  4465 			db.Close();
       
  4466 			return ETrue;
       
  4467 			}
       
  4468 		}
       
  4469 	// If the DB is already opened by message server, return ETrue.
       
  4470 	if(KErrInUse == err)
       
  4471 		{
       
  4472 		return ETrue;
       
  4473 		}
       
  4474 	db.Close();
       
  4475 	return EFalse;
       
  4476 	}
       
  4477 
       
  4478 #endif	  //#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4479