messagingfw/msgsrvnstore/server/src/MSVSERV.CPP
changeset 0 8e480a14352b
child 10 30d6238592e8
child 15 ff168ad79dda
equal deleted inserted replaced
-1:000000000000 0:8e480a14352b
       
     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)
       
   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 		else if (iNewContext->Config().iUniqueID != 0 && iNewContext->Config().iUniqueID != volume.iUniqueID)
       
  2019 			{
       
  2020 #ifndef _NO_SERVER_LOGGING_
       
  2021 			Log(_L("The media is incorrect %d != %d - using default"), iNewContext->Config().iUniqueID, volume.iUniqueID);
       
  2022 #endif
       
  2023 			// The media is incorrect - use default
       
  2024 			iStartupState = EMsvMediaIncorrect;
       
  2025 			drive = iSystemDrive;
       
  2026 			}
       
  2027 		iNewContext->CreateIndexL(drive, aSync);
       
  2028 		return;
       
  2029 		}
       
  2030 	else if (error == KErrInUse)
       
  2031 		{
       
  2032 		iIndexDrive = drive;
       
  2033 		iNewContext->CreateIndexL(drive, aSync);
       
  2034 		return;
       
  2035 		}
       
  2036 
       
  2037 	User::Leave(error);
       
  2038 	}
       
  2039 	
       
  2040 	
       
  2041 
       
  2042 	
       
  2043 EXPORT_C TInt CMsvServer::ChangeDrive(TInt aDrive, TRequestStatus* aStatus)
       
  2044 //
       
  2045 // Reload the Message Store from the specified drive
       
  2046 // If aStatus is null the index is loaded synchronously
       
  2047 // On error the index is unchanged
       
  2048 //
       
  2049 	{
       
  2050 	TRAPD(error, DoChangeDriveL(aDrive, aStatus));
       
  2051 	if (error)
       
  2052 		DeleteNewContext();
       
  2053 
       
  2054 	return error;
       
  2055 	}
       
  2056 	
       
  2057 	
       
  2058 	
       
  2059 
       
  2060 void CMsvServer::DoChangeDriveL(TInt aDrive, TRequestStatus* aStatus)
       
  2061 	{
       
  2062 	__ASSERT_ALWAYS(iContext->State() == TMsvIndexLoadProgress::EIndexComplete, PanicServer(EMsvLoadingInProgress));
       
  2063 	__ASSERT_ALWAYS(aDrive != iContext->Config().iDrive, User::Leave(KErrNotSupported));
       
  2064 	__ASSERT_DEBUG(iNewContext == NULL, PanicServer(EMsvNewContextExists));
       
  2065 
       
  2066 	if(iSearchSortCacheManager)
       
  2067 		{   
       
  2068 		iSearchSortCacheManager->ResetSearchSortCache();
       
  2069 		}
       
  2070 	iContext->IndexAdapter()->GetDbAdapter()->ClearDBContentsL();
       
  2071 
       
  2072 	// Delete any existing context
       
  2073 	DeleteNewContext();
       
  2074 	iNewContext = CMsvIndexContext::NewL(*this, *this);
       
  2075 	iNewContext->LoadStoreConfig(ETrue);
       
  2076 	iIndexDrive = aDrive;
       
  2077 
       
  2078 	if (aStatus)
       
  2079 		{
       
  2080 #ifndef _NO_SERVER_LOGGING_
       
  2081 		Log(_L("Changing drive asynchronously %d"), aDrive);
       
  2082 #endif
       
  2083 		// Load index asynchronously - will signal observer when complete
       
  2084 		iNewContext->CreateIndexL(aDrive, *aStatus);
       
  2085 		}
       
  2086 	else
       
  2087 		{
       
  2088 #ifndef _NO_SERVER_LOGGING_
       
  2089 		Log(_L("Changing drive synchronously %d"), aDrive);
       
  2090 #endif
       
  2091 		// Load index synchronously
       
  2092 		iNewContext->CreateIndexL(aDrive, ETrue);
       
  2093 
       
  2094 		// Delete the context - only relevant if an error occurs
       
  2095 		DeleteNewContext();
       
  2096 		User::LeaveIfError(iLoadError);
       
  2097 		}
       
  2098 	}
       
  2099 	
       
  2100 
       
  2101 
       
  2102 
       
  2103 void CMsvServer::BuildDefaultIniFileL(TMsvConfig& aConfig)
       
  2104 	{
       
  2105 	RFs fileSession;
       
  2106 	fileSession.Connect();
       
  2107 
       
  2108 	TInt error;
       
  2109 	TVolumeInfo volume;
       
  2110 	TUint uniqueId = 0;
       
  2111 	TChar driveChar= fileSession.GetSystemDriveChar();
       
  2112 	
       
  2113 	TBuf<2> systemDrive;
       
  2114 	systemDrive.Append(driveChar);
       
  2115 	systemDrive.Append(KDriveDelimiter);
       
  2116 	TDriveUnit driveUnit(systemDrive);
       
  2117 
       
  2118 	error = fileSession.Volume(volume, TInt(driveUnit));
       
  2119 	if (!error)
       
  2120 		{
       
  2121 		uniqueId = volume.iUniqueID;
       
  2122 		}
       
  2123 	else
       
  2124 		{
       
  2125 		User::Leave(error);
       
  2126 		}
       
  2127 
       
  2128 	TPath pathName(systemDrive);
       
  2129 	pathName.Append(KServerINIFile);
       
  2130 	CDictionaryFileStore *store=CDictionaryFileStore::OpenLC(fileSession, pathName, KNullUid);
       
  2131 
       
  2132 	RDictionaryWriteStream stream;
       
  2133 	stream.AssignLC(*store, KUidMsvMessageDriveStream);
       
  2134 
       
  2135 	//Assign the default values
       
  2136 	stream.WriteUint8L(KMsvMessageDriveStreamVersionNumber); // version number
       
  2137 	stream << systemDrive;
       
  2138 	stream.WriteUint32L(uniqueId);
       
  2139 	stream.WriteInt8L(EFalse);
       
  2140 
       
  2141 	stream.CommitL();
       
  2142 	store->CommitL();
       
  2143 	CleanupStack::PopAndDestroy(2,store); // stream, store
       
  2144 
       
  2145 	// update the values in aConfig
       
  2146 	aConfig.iDrive = driveUnit;
       
  2147 	aConfig.iUniqueID = uniqueId;
       
  2148 	aConfig.iDebug = EFalse;
       
  2149 	return; // there's no need to try to read further
       
  2150 			// values since we just made them up and
       
  2151 			// stored them here to replace the corrupt
       
  2152 			// ini file
       
  2153 	}
       
  2154 
       
  2155 
       
  2156 
       
  2157 
       
  2158 void CMsvServer::CurrentConfigL(RFs& aFs, TMsvConfig& aConfig)
       
  2159 	{
       
  2160 	TChar driveChar= aFs.GetSystemDriveChar();
       
  2161 	TBuf<2> systemDrive;
       
  2162 	systemDrive.Append(driveChar);
       
  2163 	systemDrive.Append(KDriveDelimiter);
       
  2164 	
       
  2165 	TDriveUnit driveUnit(systemDrive);  
       
  2166 	aConfig.iDrive = driveUnit;
       
  2167 	aConfig.iUniqueID = 0;
       
  2168 	aConfig.iDebug = EFalse;
       
  2169 
       
  2170 	TPath pathName(driveUnit.Name());
       
  2171 	pathName.Append(KServerINIFile);
       
  2172 	// try to open system ini
       
  2173 	CDictionaryFileStore* store = NULL;
       
  2174 	TUint unused;
       
  2175 	TInt err=aFs.Att(pathName, unused);
       
  2176 	if(err==KErrNone)
       
  2177 		{
       
  2178 		TRAPD(openIniErr,store = CDictionaryFileStore::OpenL(aFs, pathName, KNullUid));
       
  2179 		if (openIniErr == KErrCorrupt)
       
  2180 			{
       
  2181 			// The ini file has been corrupted. Delete it and create a new one
       
  2182 			aFs.Delete(pathName);
       
  2183 			RFile newIniFile;
       
  2184 			User::LeaveIfError(newIniFile.Create(aFs, pathName, EFileWrite));
       
  2185 			newIniFile.Close();
       
  2186 			BuildDefaultIniFileL(aConfig);
       
  2187 			return;
       
  2188 			}
       
  2189 		User::LeaveIfError(openIniErr);
       
  2190 		CleanupStack::PushL(store);
       
  2191 
       
  2192 		// get configuration from system ini
       
  2193 		if (store->IsPresentL(KUidMsvMessageDriveStream))
       
  2194 			{
       
  2195 			RDictionaryReadStream readStream;
       
  2196 			readStream.OpenLC(*store, KUidMsvMessageDriveStream);
       
  2197 			TInt version = readStream.ReadInt8L();
       
  2198 			// Check the drive stream version number. If invalid,
       
  2199 			// rebuild the ini file
       
  2200 			if (version > KMsvMessageDriveStreamVersionNumber)
       
  2201 				{
       
  2202 				//cleanup the corrupted info
       
  2203 				CleanupStack::PopAndDestroy(2, store);
       
  2204 
       
  2205 				//create a new ini file
       
  2206 				RFs fileSession;
       
  2207 				fileSession.Connect();
       
  2208 
       
  2209 				TInt error;
       
  2210 				TVolumeInfo volume;
       
  2211 				TUint uniqueId = 0;
       
  2212 				TDriveUnit driveUnit(systemDrive);
       
  2213 				error = fileSession.Volume(volume, TInt(driveUnit));
       
  2214 				if (!error)
       
  2215 					{
       
  2216 					uniqueId = volume.iUniqueID;
       
  2217 					}
       
  2218 				else
       
  2219 					{
       
  2220 					User::Leave(error);
       
  2221 					}
       
  2222 
       
  2223 				CDictionaryFileStore *store=CDictionaryFileStore::OpenLC(fileSession, pathName, KNullUid);
       
  2224 				RDictionaryWriteStream stream;
       
  2225 				stream.AssignLC(*store, KUidMsvMessageDriveStream);
       
  2226 
       
  2227 				//Assign the default values
       
  2228 				stream.WriteUint8L(KMsvMessageDriveStreamVersionNumber); // version number
       
  2229 				stream << systemDrive;
       
  2230 				stream.WriteUint32L(uniqueId);
       
  2231 				stream.WriteInt8L(EFalse);
       
  2232 
       
  2233 				stream.CommitL();
       
  2234 				store->CommitL();
       
  2235 				CleanupStack::PopAndDestroy(2,store); // stream, store
       
  2236 
       
  2237 				// update the values in aConfig
       
  2238 				aConfig.iDrive = driveUnit;
       
  2239 				aConfig.iUniqueID = uniqueId;
       
  2240 				aConfig.iDebug = EFalse;
       
  2241 				return; // there's no need to try to read further
       
  2242 						// values since we just made them up and
       
  2243 						// stored them here to replace the corrupt
       
  2244 						// ini file
       
  2245 				}
       
  2246 
       
  2247 			TBuf<2> drive;
       
  2248 			readStream >> drive;
       
  2249 			aConfig.iDrive = drive;
       
  2250 
       
  2251 			// The drive Id didn't exist in earlier versions
       
  2252 			if (version > 1)
       
  2253 				aConfig.iUniqueID = readStream.ReadUint32L();
       
  2254 
       
  2255 			// This debug frig wasn't in earlier versions
       
  2256 			if (version > 2)
       
  2257 				aConfig.iDebug = readStream.ReadInt8L();
       
  2258 
       
  2259 			CleanupStack::PopAndDestroy(); // readStream
       
  2260 			}
       
  2261 
       
  2262 		CleanupStack::PopAndDestroy(); // store
       
  2263 		}
       
  2264 	// remember what we loaded, so we don't have to save it if it doesn't change.
       
  2265 	// also means we don't have the defaults as they never change.
       
  2266 	aConfig.iDriveAsLoaded=aConfig.iDrive;
       
  2267 	aConfig.iDebugAsLoaded=aConfig.iDebug;
       
  2268 	aConfig.iUniqueIDAsLoaded=aConfig.iUniqueID;
       
  2269 	}
       
  2270 
       
  2271 
       
  2272 
       
  2273 
       
  2274 TBool CMsvServer::DiskRemoved(const TDriveUnit& aDrive)
       
  2275 	{
       
  2276 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  2277 #ifndef _NO_SERVER_LOGGING_
       
  2278 	Log(_L("Disk %d removed"), TInt(aDrive));
       
  2279 #endif
       
  2280 
       
  2281 	NotifyChanged(EMsvMediaUnavailable, KMsvNullIndexEntryId, TInt(aDrive));
       
  2282 	iContext->IndexAdapter()->SetErrorState(KMsvMediaUnavailable);
       
  2283 	iContext->IndexAdapter()->DeleteDbAdapter();
       
  2284 
       
  2285 	iStartupState = EMsvMediaUnavailable;
       
  2286 	return ETrue;
       
  2287 	}
       
  2288 
       
  2289 
       
  2290 
       
  2291 
       
  2292 TBool CMsvServer::DiskInserted(const TDriveUnit& aDrive)
       
  2293 	{
       
  2294 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  2295 
       
  2296 #ifndef _NO_SERVER_LOGGING_
       
  2297 	Log(_L("Disk %d inserted"), TInt(aDrive));
       
  2298 #endif
       
  2299 
       
  2300 	NotifyChanged(EMsvMediaAvailable, KMsvNullIndexEntryId, TInt(aDrive));
       
  2301 
       
  2302 	iContext->IndexAdapter()->SetErrorState(KErrNone);
       
  2303 
       
  2304 	//Need to re-open the DB when media is available (EMsvMediaAvailable).
       
  2305 	//Get current drive
       
  2306 	TInt currentDrive = 0;
       
  2307 	TRAPD(err, currentDrive = MessageServer::CurrentDriveL(iFs));
       
  2308 	if (err != KErrNone)
       
  2309 		{
       
  2310 		return EFalse;
       
  2311 		}
       
  2312 	
       
  2313 	//Get system drive
       
  2314 	TChar charDrive = FileSession().GetSystemDriveChar();
       
  2315 	TInt defaultDrive = 0;
       
  2316 	iFs.CharToDrive(charDrive, defaultDrive);
       
  2317 	TChar driveToOpen;
       
  2318 	iFs.DriveToChar(currentDrive, driveToOpen);
       
  2319 		
       
  2320 	if(currentDrive != defaultDrive)
       
  2321 		{
       
  2322 		TBuf<2> systemDrive;
       
  2323 		systemDrive.Append(driveToOpen);
       
  2324 		systemDrive.Append(KDriveDelimiter);
       
  2325 		TPath pathName(systemDrive);
       
  2326 		pathName.Append(KMsvDbFile);
       
  2327 
       
  2328 		//Re-open the DB
       
  2329 		TRAPD(error, iContext->IndexAdapter()->OpenclosedL(pathName));
       
  2330 	
       
  2331 		if(error)
       
  2332 			{
       
  2333 			#ifndef _NO_SERVER_LOGGING_
       
  2334 				Log(_L("Unable to re-open DB  "));
       
  2335 			#endif  
       
  2336 			} 
       
  2337 		}
       
  2338 
       
  2339 	iStartupState = EMsvNullNotification;
       
  2340 	return ETrue;
       
  2341 	}
       
  2342 
       
  2343 
       
  2344 
       
  2345 
       
  2346 TBool CMsvServer::DiskChanged(const TDriveUnit& aDrive, TUint)
       
  2347 	{
       
  2348 	__ASSERT_DEBUG(iContext->IndexAdapter(), PanicServer(EMsvNoIndex));
       
  2349 
       
  2350 #ifndef _NO_SERVER_LOGGING_
       
  2351 	Log(_L("Disk %d changed"), TInt(aDrive));
       
  2352 #endif
       
  2353 
       
  2354 	NotifyChanged(EMsvMediaIncorrect, KMsvNullIndexEntryId, TInt(aDrive));
       
  2355 	iContext->IndexAdapter()->SetErrorState(KMsvMediaIncorrect);
       
  2356 	iStartupState = EMsvMediaIncorrect;
       
  2357 	return ETrue;
       
  2358 	}
       
  2359 
       
  2360 
       
  2361 
       
  2362 void CMsvServer::ContextComplete(TInt aError, TBool aRunMailInit)
       
  2363 //
       
  2364 // The context has completed successfully or with failure
       
  2365 //
       
  2366 	{
       
  2367 #ifndef _NO_SERVER_LOGGING_
       
  2368 	Log(_L("Context complete with error %d"), aError);
       
  2369 #endif
       
  2370 
       
  2371 	if (!aError)
       
  2372 		{
       
  2373 		// Stop disk change notifications
       
  2374 		iNotify->Cancel();
       
  2375 
       
  2376 		// Save the new configuration
       
  2377 		iNewContext->LoadStoreConfig(EFalse); // Ignore the error
       
  2378 		TBool startup = iContext == NULL;
       
  2379 
       
  2380 		CMsvIndexContext* oldContext = iContext;
       
  2381 		iContext = iNewContext;
       
  2382 		iNewContext = NULL;
       
  2383 
       
  2384 #ifndef _NO_SERVER_LOGGING_
       
  2385 		Log(_L("Deleting iBackup"));
       
  2386 #endif
       
  2387 		if(iBackup == NULL)
       
  2388 			{
       
  2389 			// To Gracefully handle and to register with the backup server.
       
  2390 			TRAP_IGNORE(iBackup=CMsvBackupHandler::NewL(*this));
       
  2391 			}
       
  2392 
       
  2393 		// Check for presence of MailInit not completed flag
       
  2394 		iFs.SetSessionToPrivate(iContext->Config().iDrive);
       
  2395 		TUint unused;
       
  2396 		TBool initNotCompleted = (iFs.Att(KMsvStoreInitFileName, unused)!=KErrNotFound);
       
  2397 		if ((initNotCompleted || aRunMailInit) && !(iDebug || iContext->Config().iDebug))
       
  2398 			RunMailInitExe();
       
  2399 
       
  2400 
       
  2401 		// Send index ready notification
       
  2402 		NotifyChanged(EMsvIndexLoaded);
       
  2403 
       
  2404 		if (!startup)
       
  2405 			{
       
  2406 			// Send disk change notification
       
  2407 			NotifyChanged(EMsvMediaChanged, KMsvNullIndexEntryId, TInt(oldContext->Config().iDrive), TInt(iContext->Config().iDrive));
       
  2408 			}
       
  2409 		else
       
  2410 			{
       
  2411 			// Send disk change notifications if drive changed
       
  2412 			if (iStartupState != EMsvNullNotification && TInt(iIndexDrive) != TInt(iContext->Config().iDrive))
       
  2413 				{
       
  2414 				NotifyChanged(iStartupState, KMsvNullIndexEntryId, TInt(iIndexDrive));
       
  2415 				NotifyChanged(EMsvMediaChanged, KMsvNullIndexEntryId, TInt(iIndexDrive), TInt(iContext->Config().iDrive));
       
  2416 				}
       
  2417 
       
  2418 			}
       
  2419 
       
  2420 		// Reset the index error state
       
  2421 		iContext->IndexAdapter()->SetErrorState(KErrNone);
       
  2422 		iStartupState = EMsvNullNotification;
       
  2423 		delete oldContext;
       
  2424 		}
       
  2425 
       
  2426 	if (iContext && iContext->Config().iDrive.Name().CompareF(iSystemDrive) != 0 && !iNotify->IsActive())
       
  2427 		{
       
  2428 		// Restart disk change notifications
       
  2429 		iNotify->Start(iContext->Config().iDrive, iContext->Config().iUniqueID);
       
  2430 		}
       
  2431 
       
  2432 	// Remember the error
       
  2433 	iLoadError = aError;
       
  2434 	}
       
  2435 
       
  2436 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2437 
       
  2438 
       
  2439 
       
  2440 
       
  2441 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2442 void CMsvServer::RunMailInitExe(TDriveNumber aDriveNum)
       
  2443 #else
       
  2444 void CMsvServer::RunMailInitExe()
       
  2445 #endif
       
  2446 //
       
  2447 //
       
  2448 //
       
  2449 	{
       
  2450 #ifndef _NO_SERVER_LOGGING_
       
  2451 	Log(_L("Running mailinit"));
       
  2452 #endif
       
  2453 	_LIT8(KMsvStoreInitTestData,"StoreInit");
       
  2454 	RFile storeInitFile;
       
  2455 
       
  2456 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT) 
       
  2457 	iFs.SetSessionToPrivate(aDriveNum);
       
  2458 #else
       
  2459 	iFs.SetSessionToPrivate(iContext->Config().iDrive);
       
  2460 #endif
       
  2461 
       
  2462 	if (storeInitFile.Replace(iFs, KMsvStoreInitFileName, EFileShareAny|EFileWrite)==KErrNone)
       
  2463 		storeInitFile.Write(KMsvStoreInitTestData);
       
  2464 	storeInitFile.Close();
       
  2465 	// NOTE! MailInit.exe MUST delete this file otherwise MailInit will be run each time the
       
  2466 	//	   message server is started.
       
  2467 	// this note is only true for releases before v9.0
       
  2468 
       
  2469 	_LIT(KMsvPostInitialisationSearchPattern, "*MAILINIT*");
       
  2470 	_LIT(KMsvPostInitialisationProcessPattern, "*");
       
  2471 	RProcess p;
       
  2472 	TFindProcess finder;
       
  2473 #define CREATE_PROCESS_OR_THREAD() p.Create(KMsvPostInitialisationExe, TPtr(NULL,0), TUidType(KNullUid, KNullUid, KMsvMailInitExeUid))
       
  2474 
       
  2475 
       
  2476 #ifndef _NO_SERVER_LOGGING_
       
  2477 	Log(_L("Checking for mailinit process/thread"));
       
  2478 #endif
       
  2479 
       
  2480 	TFullName fullName;
       
  2481 	TBool found = EFalse;
       
  2482 	finder.Find(KMsvPostInitialisationProcessPattern);
       
  2483 	while (finder.Next(fullName) == KErrNone && !found)
       
  2484 		{
       
  2485 		fullName.UpperCase();
       
  2486 		if (fullName.Match(KMsvPostInitialisationSearchPattern) != KErrNotFound)
       
  2487 			{
       
  2488 #ifndef _NO_SERVER_LOGGING_
       
  2489 			Log(_L("Mailinit (%S) found"), &fullName);
       
  2490 #endif
       
  2491 			found = ETrue;
       
  2492 			break;
       
  2493 			}
       
  2494 		}
       
  2495 
       
  2496 	if (!found)
       
  2497 		{
       
  2498 #ifndef _NO_SERVER_LOGGING_
       
  2499 		Log(_L("Mailinit not detected, running"));
       
  2500 #endif
       
  2501 		if (CREATE_PROCESS_OR_THREAD() == KErrNone)
       
  2502 			{
       
  2503 			p.Resume();
       
  2504 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT) 
       
  2505 			iMailinitWaiter->WaitFor(p, aDriveNum);
       
  2506 #else
       
  2507 			iMailinitWaiter->WaitFor(p, (TDriveNumber) (TInt)(iContext->Config().iDrive));
       
  2508 #endif		  
       
  2509 
       
  2510 #ifndef _NO_SERVER_LOGGING_
       
  2511 			Log(_L("Mailinit run"));
       
  2512 #endif
       
  2513 			}
       
  2514 		}
       
  2515 	}
       
  2516 
       
  2517 
       
  2518 CSession2* CMsvServer::DoNewSessionL(const RMessage2 &aMessage)
       
  2519 //
       
  2520 //
       
  2521 //
       
  2522 	{
       
  2523 	if (iCloseServer)
       
  2524 		{
       
  2525 #ifndef _NO_SERVER_LOGGING_
       
  2526 		Log(_L("New session requested whilst waiting to close!"));
       
  2527 #endif
       
  2528 		User::Leave(KErrServerBusy);
       
  2529 		}
       
  2530 
       
  2531 	// create the session
       
  2532 	CMsvServerSession* ses = CMsvServerSession::NewL(*this, aMessage);
       
  2533 
       
  2534 #ifndef _NO_SERVER_LOGGING_
       
  2535 	Log(_L("New session created for process %S"), &ses->ProcessName());
       
  2536 #endif
       
  2537 
       
  2538 #ifdef MSG_SERV_AUTO_CLOSE
       
  2539 	// cancel the close down timer
       
  2540 	iCloseTimer->Cancel();
       
  2541 #endif
       
  2542 
       
  2543 	return ses;
       
  2544 	}
       
  2545 
       
  2546 
       
  2547 CSession2 *CMsvServer::NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
       
  2548 	{
       
  2549 	// check we're the right version
       
  2550 	TVersion v(KMsvServerMajorVersionNumber,KMsvServerMinorVersionNumber,KMsvServerBuildVersionNumber);
       
  2551 	if (!User::QueryVersionSupported(v,aVersion))
       
  2552 		User::Leave(KErrNotSupported);
       
  2553 
       
  2554 	// create the index if not already done
       
  2555 	return ((CMsvServer*)this)->DoNewSessionL(aMessage);
       
  2556 	}
       
  2557 
       
  2558 void CMsvServer::CompleteBulkTransaction(void)
       
  2559 	{
       
  2560 	iContext->IndexAdapter()->CommitNonCommitedEntries();
       
  2561 	TRAP_IGNORE(NotifyChangedBulkL());
       
  2562 	}
       
  2563 
       
  2564 void CMsvServer::NotifyChangedBulkL()
       
  2565 	{
       
  2566 	// send notifications for the created entries
       
  2567 	DoNotifyChangedBulkL(EMsvEntriesCreated, *iBulkCreationSelection);
       
  2568 
       
  2569 
       
  2570 	// send notifications for the changed entries
       
  2571 	CMsvEntrySelection* selection = new(ELeave) CMsvEntrySelection();
       
  2572 	CleanupStack::PushL(selection);
       
  2573 	TInt bulkChangeCount = iBulkChangeSelection->Count();
       
  2574 	selection->SetReserveL(bulkChangeCount);
       
  2575 
       
  2576 	// no need to notify entries which have already been notified (by the create notification)
       
  2577 	TMsvId changedId = 0;
       
  2578 	for (TInt ii=0; ii<bulkChangeCount; ++ii)
       
  2579 		{
       
  2580 		changedId = iBulkChangeSelection->At(ii);
       
  2581 		if (iBulkCreationSelection->Find(changedId) == KErrNotFound)
       
  2582 			{
       
  2583 			selection->AppendL(changedId);
       
  2584 			}
       
  2585 		}
       
  2586 
       
  2587 	DoNotifyChangedBulkL(EMsvEntriesChanged, *selection);
       
  2588 
       
  2589 	iBulkCreationSelection->Reset();
       
  2590 	iBulkChangeSelection->Reset();
       
  2591 	CleanupStack::PopAndDestroy(selection);
       
  2592 	}
       
  2593 
       
  2594 void CMsvServer::DoNotifyChangedBulkL(TMsvServerChangeNotificationType aChangeType, const CMsvEntrySelection& aEntriesToNotify)
       
  2595 	{
       
  2596 	TInt entriesToNotifyCount = aEntriesToNotify.Count();
       
  2597 	if( entriesToNotifyCount > 0 )
       
  2598 		{
       
  2599 		//Check whether all entries has the same parent id
       
  2600 		//If not send individual notifications
       
  2601 		CMsvEntrySelection* selection = new(ELeave) CMsvEntrySelection();
       
  2602 		CleanupStack::PushL(selection);
       
  2603 
       
  2604 		// Reserve the maximum space required - avoid leaves later on.
       
  2605 		selection->SetReserveL(entriesToNotifyCount);
       
  2606 
       
  2607 		TMsvId id;
       
  2608 		TMsvId parentId = KMsvNullIndexEntryId;
       
  2609 		TMsvId tempParentId = KMsvNullIndexEntryId;
       
  2610 		TMsvEntry* entryPtr;
       
  2611 		TInt error;
       
  2612 		TBool foundOne(EFalse);
       
  2613 
       
  2614 		for (TInt i = 0; i < entriesToNotifyCount; ++i)
       
  2615 			{
       
  2616 			id = aEntriesToNotify.At(i);
       
  2617 			error = IndexAdapter().GetEntry(id, entryPtr);
       
  2618 			if (error == KErrNone)
       
  2619 				{
       
  2620 				tempParentId = entryPtr->Parent();
       
  2621 
       
  2622 				if (foundOne)
       
  2623 					{
       
  2624 					// We have found a previously valid entry. If this
       
  2625 					// new entry has a different parent to the previous one,
       
  2626 					// send the notifications now using the old parent and
       
  2627 					// start again with the new parent.
       
  2628 					if (tempParentId != parentId)
       
  2629 						{
       
  2630 						NotifyChanged(aChangeType, *selection, parentId);
       
  2631 						selection->Reset();
       
  2632 						parentId = tempParentId;
       
  2633 						}
       
  2634 					}
       
  2635 				else
       
  2636 					{
       
  2637 					// This is the first valid entry we have found. Store its parent
       
  2638 					// as we need to see if the next entry has the same parent as well
       
  2639 					foundOne = ETrue;
       
  2640 					parentId = tempParentId;
       
  2641 					}
       
  2642 
       
  2643 				selection->AppendL(id);
       
  2644 				}
       
  2645 			}
       
  2646 
       
  2647 		if (selection->Count() != 0)
       
  2648 			{
       
  2649 			NotifyChanged(aChangeType, *selection, parentId);
       
  2650 			}
       
  2651 
       
  2652 		CleanupStack::PopAndDestroy(selection);
       
  2653 		}
       
  2654 	}
       
  2655 
       
  2656 void CMsvServer::PoliceReadEntryL(const RMessage2& aMsg, TSecureId aOwnerId, const char* aContextText)
       
  2657 	{
       
  2658 	// The client can read the entry under following circumstances.
       
  2659 	// 1. The client has Read User Data capability.
       
  2660 	// 2. The client does not have Read User Data but owns the entry.
       
  2661 
       
  2662 	// First check if the client is trusted with Read User Data.
       
  2663 	if( !aMsg.HasCapability(ECapabilityReadUserData) )
       
  2664 		{
       
  2665 		// Client not trusted with Read User data - check that it owns the entry.
       
  2666 		if( aMsg.SecureId() != aOwnerId )
       
  2667 			{
       
  2668 			// Client missing capabilities - emit diagnostics and leave...
       
  2669 			User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, ECapabilityReadUserData, aContextText));
       
  2670 			}
       
  2671 		}
       
  2672 	}
       
  2673 
       
  2674 void CMsvServer::PoliceReadEntryL(const RMessage2& aMsg, TMsvId aId, const char* aContextText)
       
  2675 	{
       
  2676 	// The client can read the entry under following circumstances.
       
  2677 	// 1. The client has Read User Data capability.
       
  2678 	// 2. The client does not have Read User Data but owns the entry.
       
  2679 
       
  2680 	// First check if the client is trusted with Read User Data.
       
  2681 	if( !aMsg.HasCapability(ECapabilityReadUserData) )
       
  2682 		{
       
  2683 		// Client not trusted with Read User data - check that it owns the entry.
       
  2684 		TMsvEntry* entryPtrNotUsed;
       
  2685 		TSecureId ownerId;
       
  2686 		TInt error = IndexAdapter().GetEntry(aId, entryPtrNotUsed, ownerId);
       
  2687 		if( aMsg.SecureId() != ownerId )
       
  2688 			{
       
  2689 			// Client missing capabilities - emit diagnostics and leave...
       
  2690 			User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, ECapabilityReadUserData, aContextText));
       
  2691 			}
       
  2692 		}
       
  2693 	}
       
  2694 
       
  2695 void CMsvServer::PoliceCreateEntryL(const RMessage2& aMsg, TMsvEntry aEntry, TBool& aIsLocal, const char* aContextText)
       
  2696 	{
       
  2697 	// Get the parent entry info...
       
  2698 	CMsvIndexAdapter::TMsvServerEntryInfo info;
       
  2699 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aEntry.Parent(), info));
       
  2700 	// Change the MTM and type to that specified in aEntry...
       
  2701 	info.iType  = aEntry.iType;
       
  2702 	info.iMtm   = aEntry.iMtm;
       
  2703 
       
  2704 	PoliceCreateModifyEntryL(aMsg, info, ETrue, aIsLocal, aContextText);
       
  2705 	}
       
  2706 
       
  2707 void CMsvServer::PoliceModifyEntryL(const RMessage2& aMsg, TMsvEntry aEntry, TBool& aIsLocal, const char* aContextText)
       
  2708 	{
       
  2709 	// Get the entry info...
       
  2710 	CMsvIndexAdapter::TMsvServerEntryInfo info;
       
  2711 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aEntry.Id(), info));
       
  2712 	// Change the MTM and type to that specified in aEntry...
       
  2713 	info.iType  = aEntry.iType;
       
  2714 	info.iMtm   = aEntry.iMtm;
       
  2715 
       
  2716 	PoliceCreateModifyEntryL(aMsg, info, EFalse, aIsLocal, aContextText);
       
  2717 	}
       
  2718 
       
  2719 void CMsvServer::PoliceModifyEntryL(const RMessage2& aMsg, TMsvId aId, TBool& aIsLocal, const char* aContextText)
       
  2720 	{
       
  2721 	// Get the entry info...
       
  2722 	CMsvIndexAdapter::TMsvServerEntryInfo info;
       
  2723 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aId, info));
       
  2724 	PoliceCreateModifyEntryL(aMsg, info, EFalse, aIsLocal, aContextText);
       
  2725 	}
       
  2726 
       
  2727 void CMsvServer::PoliceModifyEntryL(const RMessage2& aMsg, TMsvId aId, const char* aContextText)
       
  2728 	{
       
  2729 	TBool notUsed;
       
  2730 	PoliceModifyEntryL(aMsg, aId, notUsed, aContextText);
       
  2731 	}
       
  2732 
       
  2733 
       
  2734 void CMsvServer::PoliceCreateModifyEntryL(const RMessage2& aMsg, CMsvIndexAdapter::TMsvServerEntryInfo aEntryInfo, TBool aCreate, TBool& aIsLocal, const char* aContextText)
       
  2735 	{
       
  2736 	TCapabilitySet caps;
       
  2737 
       
  2738 	// The entry is local if the service is the local service.
       
  2739 	aIsLocal = aEntryInfo.iService == KMsvLocalServiceIndexEntryId;
       
  2740 
       
  2741 	// Check if a service entry or non-service entry is being created.
       
  2742 	if( aEntryInfo.iType != KUidMsvServiceEntry && aEntryInfo.iType != KUidMsvRootEntry )
       
  2743 		{
       
  2744 		// When creating/modifying an under local service, use the entry MTM
       
  2745 		// but under a remote service, use the remote service MTM.
       
  2746 		TUid mtm = aIsLocal ? aEntryInfo.iMtm : aEntryInfo.iServiceMtm;
       
  2747 
       
  2748 		// If creating an entry, check against the parent owner ID, but modifying
       
  2749 		// an entry, check against the entry owner ID.
       
  2750 		TSecureId ownerId = aCreate ? aEntryInfo.iParentOwnerId : aEntryInfo.iEntryOwnerId;
       
  2751 
       
  2752 		// If creating an entry, the create flag depends on whether the entry
       
  2753 		// is being created under an existing message.
       
  2754 		TBool create = aCreate ? !aEntryInfo.iPartOfMessage : EFalse;
       
  2755 
       
  2756 		// Given all the info, go get the required capabilities.
       
  2757 		GetCapsEntryCreateModifyL(aMsg, aEntryInfo.iTopFolder, mtm, ownerId, create, aIsLocal, caps);
       
  2758 		}
       
  2759 	else
       
  2760 		{
       
  2761 		// Client requires write device data to create/modify a service entry.
       
  2762 		caps.SetEmpty();
       
  2763 		caps.AddCapability(ECapabilityWriteDeviceData);
       
  2764 		}
       
  2765 	// Ok, have the required capabilities - check the client capabilities
       
  2766 	TSecurityInfo clientInfo(aMsg);
       
  2767 
       
  2768 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2769 		{
       
  2770 		// Client missing capabilities - emit diagnostics and leave...
       
  2771 		caps.Remove(clientInfo.iCaps);
       
  2772 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2773 		}
       
  2774 	}
       
  2775 
       
  2776 void CMsvServer::PoliceMoveEntriesL(const RMessage2& aMsg, const CMsvEntrySelection& aSelection, TMsvId aTarget, TMsvId aSource, TBool& aTargetIsLocal, TBool& aSourceIsLocal, const char* aContextText)
       
  2777 	{
       
  2778 	// To police a move entries request, the client must be able to modify both
       
  2779 	// the target entry and the source entry. In the case of the target entry,
       
  2780 	// the client is essentially creating entries under the target entry.
       
  2781 
       
  2782 	// Checking the target is the same as for a copy...
       
  2783 
       
  2784 #if (defined SYMBIAN_USER_PROMPT_SERVICE)
       
  2785 	TRAPD(err, PoliceCopyEntriesL(aMsg, aSelection, aTarget, aTargetIsLocal, aContextText));
       
  2786 	if(err != KErrPermissionDenied)
       
  2787 		{
       
  2788 		User::LeaveIfError(err);
       
  2789 		}
       
  2790 #else
       
  2791 	PoliceCopyEntriesL(aMsg, aSelection, aTarget, aTargetIsLocal, aContextText);
       
  2792 #endif
       
  2793 	
       
  2794 	// Get the entry into the source entry...
       
  2795 	CMsvIndexAdapter::TMsvServerEntryInfo sourceInfo;
       
  2796 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aSource, sourceInfo));
       
  2797 	// Police the modification of source entry.
       
  2798 	PoliceCreateModifyEntryL(aMsg, sourceInfo, EFalse, aSourceIsLocal, aContextText);
       
  2799 #if (defined SYMBIAN_USER_PROMPT_SERVICE)
       
  2800 	if(err != KErrNone && aSourceIsLocal && aTargetIsLocal)
       
  2801 		{
       
  2802 		User::LeaveIfError(err);
       
  2803 		}
       
  2804 #endif
       
  2805 	}
       
  2806 
       
  2807 void CMsvServer::PoliceCopyEntriesL(const RMessage2& aMsg, const CMsvEntrySelection& aSelection, TMsvId aTarget, TBool& aTargetIsLocal, const char* aContextText)
       
  2808 	{
       
  2809 	// To police a copy entries request, the client must be able to modify the
       
  2810 	// target entry - essentially it is creating entries under the target entry.
       
  2811 
       
  2812 	// Get the entry info for target entry...
       
  2813 	CMsvIndexAdapter::TMsvServerEntryInfo targetInfo;
       
  2814 	User::LeaveIfError(iContext->IndexAdapter()->EntryTreeInfo(aTarget, targetInfo));
       
  2815 	// The policing strategy changes slightly if the target is the outbox or a
       
  2816 	// folder under the outbox that is not part of a message.
       
  2817 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2818 	TMsvId topFolderId = UnmaskTMsvId(targetInfo.iTopFolder);
       
  2819 #else
       
  2820 	TMsvId topFolderId = targetInfo.iTopFolder;
       
  2821 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2822 	
       
  2823 	if( topFolderId == KMsvGlobalOutBoxIndexEntryId &&
       
  2824 		targetInfo.iType == KUidMsvFolderEntry && !targetInfo.iPartOfMessage )
       
  2825 		{
       
  2826 		aTargetIsLocal = ETrue;
       
  2827 		PoliceCopyMoveUnderOutboxL(aMsg, aSelection, aContextText);
       
  2828 		}
       
  2829 	else
       
  2830 		{
       
  2831 		// Police the modification of target entry. NOTE - check client can
       
  2832 		// create entries under target.
       
  2833 		PoliceCreateModifyEntryL(aMsg, targetInfo, ETrue, aTargetIsLocal, aContextText);
       
  2834 		}
       
  2835 	}
       
  2836 
       
  2837 void CMsvServer::PoliceCopyMoveUnderOutboxL(const RMessage2& aMsg, const CMsvEntrySelection& aSelection, const char* aContextText)
       
  2838 	{
       
  2839 	// The target is either the outbox itself or a folder under the outbox
       
  2840 	// that is not part of message. In this case need to police the request
       
  2841 	// against the capabilities specified by the MTM of each entry in the
       
  2842 	// seleciton as well as read/write user data.
       
  2843 	TCapabilitySet caps;
       
  2844 	caps.SetEmpty();
       
  2845 
       
  2846 	TInt count = aSelection.Count();
       
  2847 	for( TInt i=0; i<count; ++i )
       
  2848 		{
       
  2849 		TMsvEntry* entryPtr;
       
  2850 		User::LeaveIfError(iContext->IndexAdapter()->GetEntry(aSelection.At(i), entryPtr));
       
  2851 		// Get the capabilities specified by the MTM of the entry and add them
       
  2852 		// to the total required set.
       
  2853 		TCapabilitySet mtmCaps;
       
  2854 		GetCapsForMtmL(entryPtr->iMtm, mtmCaps);
       
  2855 		caps.Union(mtmCaps);
       
  2856 		}
       
  2857 	if( ProtectedFolder(KMsvGlobalOutBoxIndexEntryId) )
       
  2858 		{
       
  2859 		// The outbox is protected - need read/write user data capabilities.
       
  2860 		caps.AddCapability(ECapabilityReadUserData);
       
  2861 		caps.AddCapability(ECapabilityWriteUserData);
       
  2862 		}
       
  2863 	// Ok, have the required capabilities - check the client capabilities
       
  2864 	TSecurityInfo clientInfo(aMsg);
       
  2865 
       
  2866 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2867 		{
       
  2868 		// Client missing capabilities - emit diagnostics and leave...
       
  2869 		caps.Remove(clientInfo.iCaps);
       
  2870 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2871 		}
       
  2872 	}
       
  2873 
       
  2874 void CMsvServer::PoliceMtmTransferCommandL(const RMessage2& aMsg, TUid aMtm, const char* aContextText)
       
  2875 	{
       
  2876 	// To access the functionality of a server MTM, a client is required to be
       
  2877 	// trusted with read and write user data as well as the capabilities
       
  2878 	// specified by the server MTM.
       
  2879 	TCapabilitySet caps;
       
  2880 	GetMtmRequiredCapabilitiesL(aMtm, caps);
       
  2881 	caps.AddCapability(ECapabilityReadUserData);
       
  2882 	caps.AddCapability(ECapabilityWriteUserData);
       
  2883 
       
  2884 	// Ok, have the required capabilities - check the client capabilities
       
  2885 	TSecurityInfo clientInfo(aMsg);
       
  2886 
       
  2887 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2888 		{
       
  2889 		// Client missing capabilities - emit diagnostics and leave...
       
  2890 		caps.Remove(clientInfo.iCaps);
       
  2891 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2892 		}
       
  2893 	}
       
  2894 
       
  2895 void CMsvServer::PoliceStopServiceL(const RMessage2& aMsg, TUid aMtm, const char* aContextText)
       
  2896 	{
       
  2897 	// To stop a service, a client is required to be trusted with the capabilities
       
  2898 	// specified by the server MTM.
       
  2899 	TCapabilitySet caps;
       
  2900 	GetMtmRequiredCapabilitiesL(aMtm, caps);
       
  2901 
       
  2902 	// Ok, have the required capabilities - check the client capabilities
       
  2903 	TSecurityInfo clientInfo(aMsg);
       
  2904 
       
  2905 	if( !clientInfo.iCaps.HasCapabilities(caps) )
       
  2906 		{
       
  2907 		// Client missing capabilities - emit diagnostics and leave...
       
  2908 		caps.Remove(clientInfo.iCaps);
       
  2909 		User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, caps, aContextText));
       
  2910 		}
       
  2911 	}
       
  2912 
       
  2913 TBool CMsvServer::ProtectedFolder(TMsvId aFolder) const
       
  2914 	{
       
  2915 	TInt index = iProtectedFolders.Count();
       
  2916 	while( index-- > 0 )
       
  2917 		{
       
  2918 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2919 		if( UnmaskTMsvId(aFolder) == iProtectedFolders[index] )
       
  2920 #else
       
  2921 		if( aFolder == iProtectedFolders[index] )
       
  2922 #endif
       
  2923 			{
       
  2924 			return ETrue;
       
  2925 			}
       
  2926 		}
       
  2927 	return EFalse;
       
  2928 	}
       
  2929 
       
  2930 TBool CMsvServer::ProtectedRemoteServices() const
       
  2931 	{
       
  2932 	return iRemoteServicesProtected;
       
  2933 	}
       
  2934 
       
  2935 void CMsvServer::GetCapsEntryCreateModifyL(const RMessage2& aMsg, TMsvId aFolder, TUid aMtm, TSecureId aOwnerId, TBool aCreateEntry, TBool aLocal, TCapabilitySet& aCaps)
       
  2936 	{
       
  2937 	// Checks what capabilities are required to create/modify an entry under
       
  2938 	// the local for a given type of MTM under the specified folder or under a
       
  2939 	// remote service of given type of MTM.
       
  2940 	//
       
  2941 	// 1. Protected	 - read/write user data.
       
  2942 	// 2. Unprotected   - for creating an entry or modifying an entry that is
       
  2943 	// owned by the client, no capabilities are required, but if modifying an
       
  2944 	// entry not owned by the client then read/write user data is required.
       
  2945 	//
       
  2946 	// Additional capabilities required whether entry under local service or a
       
  2947 	// remote service -
       
  2948 	// 1. Local service - if the entry is under the outbox then the capabilities
       
  2949 	// specified by the MTM are required.
       
  2950 	// 2  Remote service - the capabilities specified by the MTM of the remote
       
  2951 	// entry are required.
       
  2952 	aCaps.SetEmpty();
       
  2953 
       
  2954 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2955 	if( !aLocal || UnmaskTMsvId(aFolder) == KMsvGlobalOutBoxIndexEntryId )
       
  2956 #else
       
  2957 	if( !aLocal || aFolder == KMsvGlobalOutBoxIndexEntryId )
       
  2958 #endif
       
  2959 
       
  2960 		{
       
  2961 		__ASSERT_DEBUG( aMtm != KUidMsvNullEntry, User::Invariant() );
       
  2962 		if( aMtm == KUidMsvNullEntry )
       
  2963 			User::Leave(KErrNotSupported);
       
  2964 
       
  2965 		// Entry being created/modified under the outbox or under a remote service
       
  2966 		// - need the capabilities specified by the MTM.
       
  2967 		GetCapsForMtmL(aMtm, aCaps);
       
  2968 		}
       
  2969 	if( !aLocal && ProtectedRemoteServices() ||
       
  2970 		ProtectedFolder(aFolder) || (!aCreateEntry && aMsg.SecureId()!=aOwnerId) )
       
  2971 		{
       
  2972 		// An entry being created/modified under a protected folder or an entry
       
  2973 		// that is not owned by the client and under an unprotected folder is
       
  2974 		// being modified - need read/write user data capabilities.
       
  2975 		//
       
  2976 		// NOTE - the remote servive is considered protected if the Outbox is
       
  2977 		// protected.
       
  2978 		aCaps.AddCapability(ECapabilityReadUserData);
       
  2979 		aCaps.AddCapability(ECapabilityWriteUserData);
       
  2980 		}
       
  2981 	}
       
  2982 
       
  2983 void CMsvServer::GetCapsForMtmL(TUid aMtm, TCapabilitySet& aCaps)
       
  2984 	{
       
  2985 	// Entry being created/modified under the outbox or under a remote service
       
  2986 	// - need the capabilities specified by the MTM. Check the following
       
  2987 	// 1. MTM is present - if not then by specify the default capabilties of
       
  2988 	// Network Services and Local Services.
       
  2989 	// 2. MTM is not the local service MTM - query the capabilities from the
       
  2990 	// MTM registry.
       
  2991 	// 3. MTM is the local service MTM - no added capabilities required.
       
  2992 	if( aMtm != KUidMsvLocalServiceMtm )
       
  2993 		{
       
  2994 		if( !iServerMtmReg->IsPresent(aMtm) )
       
  2995 			{
       
  2996 			// The MTM is not present - default to Network Services and Local
       
  2997 			// Services.
       
  2998 			aCaps.SetEmpty();
       
  2999 			aCaps.AddCapability(ECapabilityNetworkServices);
       
  3000 			aCaps.AddCapability(ECapabilityLocalServices);
       
  3001 			}
       
  3002 		else
       
  3003 			{
       
  3004 			// The MTM is present and not the local service MTM - query the MTM
       
  3005 			// registry for the required capabilities.
       
  3006 			GetMtmRequiredCapabilitiesL(aMtm, aCaps);
       
  3007 			}
       
  3008 		}
       
  3009 	}
       
  3010 
       
  3011 
       
  3012 
       
  3013 void CMsvServer::NotifyChanged(TMsvServerChangeNotificationType aChangeType, const CMsvEntrySelection& aSelection, TInt aParameter1, TInt aParameter2)
       
  3014 	{
       
  3015 	TMsvPackedChangeNotification package(iChange);
       
  3016 	TInt finish=0;
       
  3017 	do
       
  3018 		{
       
  3019 		TInt start=finish;
       
  3020 		finish = Min(finish + TMsvPackedChangeNotification::KMsvPackedChangeLimit, aSelection.Count());
       
  3021 		package.Pack(aChangeType, aSelection, aParameter1, aParameter2, start, finish-1);
       
  3022 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3023 		iNotification = aChangeType;
       
  3024 #endif
       
  3025 		DoNotify(aChangeType);
       
  3026 		}
       
  3027 	while (finish < aSelection.Count());
       
  3028 	}
       
  3029 
       
  3030 
       
  3031 void CMsvServer::NotifyChanged(TMsvServerChangeNotificationType aChangeType, TMsvId aId, TInt aParameter1, TInt aParameter2)
       
  3032 	{
       
  3033 	TMsvPackedChangeNotification package(iChange);
       
  3034 	package.Pack(aChangeType, aId, aParameter1, aParameter2);
       
  3035 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3036 	iNotification = aChangeType;
       
  3037 #endif
       
  3038 	DoNotify(aChangeType);
       
  3039 	}
       
  3040 
       
  3041 void CMsvServer::NotifyChanged(TMsvServerChangeNotificationType aChangeType, TUid aMtmTypeUid)
       
  3042 	{
       
  3043 	TMsvPackedChangeNotification package(iChange);
       
  3044 	package.Pack(aChangeType, 0, aMtmTypeUid.iUid, 0);
       
  3045 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3046 	iNotification = aChangeType;
       
  3047 #endif
       
  3048 	DoNotify(aChangeType);
       
  3049 	}
       
  3050 
       
  3051 void CMsvServer::QueueNotifyChanged(TMsvServerChangeNotificationType aChangeType)
       
  3052 	{
       
  3053 	TMsvPackedChangeNotification package(iChange);
       
  3054 	package.Pack(aChangeType, 0, 0, 0);
       
  3055 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  3056 	iNotification = aChangeType;
       
  3057 #endif
       
  3058 	DoNotify(aChangeType,ETrue);
       
  3059 	}
       
  3060 
       
  3061 void CMsvServer::DoNotify(TMsvServerChangeNotificationType aChangeType,TBool aQueue)
       
  3062 //
       
  3063 // pass the information to each session
       
  3064 //
       
  3065 	{
       
  3066 	iSessionIter.SetToFirst();
       
  3067 	CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3068 	while (ses!=NULL)
       
  3069 		{
       
  3070 #ifndef _NO_SERVER_LOGGING_
       
  3071 		Log(_L("Notifying session, process %S"), &ses->ProcessName());
       
  3072 #endif
       
  3073 		// will only leave if the write to the client fails - so no problem ignoring
       
  3074 		// the leave as the client will have been panic'd anyway
       
  3075 		if(ses->ReceiveEntryEvents() ||
       
  3076 			(aChangeType!=EMsvEntriesCreated &&
       
  3077 			 aChangeType!=EMsvEntriesChanged &&
       
  3078 			 aChangeType!=EMsvEntriesDeleted &&
       
  3079 			 aChangeType!=EMsvEntriesMoved))
       
  3080 			{
       
  3081 			TRAP_IGNORE(ses->NotifyChangedL(iChange, aQueue));
       
  3082 			}
       
  3083 
       
  3084 		ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3085 		}
       
  3086 	}
       
  3087 
       
  3088 TInt CMsvServer::GetEntryName(TMsvId aId, TDes& aFileName, TBool aFolderRequired)
       
  3089 //
       
  3090 // Construct the entry filename
       
  3091 //
       
  3092 	{
       
  3093 	return GetEntryName(*iContext, aId, aFileName, aFolderRequired);
       
  3094 	}
       
  3095 
       
  3096 TInt CMsvServer::GetEntryName(const CMsvIndexContext& aContext, TMsvId aId, TDes& aFileName, TBool aFolderRequired)
       
  3097 //
       
  3098 // Construct the entry filename with the given context
       
  3099 //
       
  3100 	{
       
  3101 	// set up the basic path
       
  3102 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3103 	aContext.MessageFolder(GetDriveId(aId), aFileName);
       
  3104 #else
       
  3105 	aFileName = aContext.MessageFolder();
       
  3106 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3107 
       
  3108 	TInt error=KErrNone;
       
  3109 	TMsvId service=KMsvRootIndexEntryId;
       
  3110 	if (aId!=KMsvRootIndexEntryId)
       
  3111 		{
       
  3112 		error = aContext.IndexAdapter()->OwningService(aId, service);
       
  3113 		}
       
  3114 
       
  3115 	if (error==KErrNone)
       
  3116 		MsvUtils::ConstructEntryName(service, aId, aFileName, (aFolderRequired ? MsvUtils::EFolder : MsvUtils::EStore));
       
  3117 	return error;
       
  3118 	}
       
  3119 
       
  3120 
       
  3121 TInt CMsvServer::GetAndMakeFileDirectory(TMsvId aId, TDes& aDirectory)
       
  3122 //
       
  3123 // Constructs the name of the directory for files associated with the entry id,
       
  3124 // and makes the directory if it doesn't exist
       
  3125 //
       
  3126 	{
       
  3127 	TInt error = GetEntryName(aId, aDirectory, ETrue);
       
  3128 	if (error==KErrNone)
       
  3129 		error = iFs.MkDirAll(aDirectory);
       
  3130 	return (error==KErrAlreadyExists ? KErrNone : error);
       
  3131 	}
       
  3132 
       
  3133 TInt CMsvServer::GetFileDirectoryListing(TMsvId aId, TDes& aDirectory, CDir*& aDir)
       
  3134 //
       
  3135 //
       
  3136 //
       
  3137 	{
       
  3138 	TInt error = GetEntryName(aId, aDirectory, ETrue);
       
  3139 	if (error==KErrNone)
       
  3140 		error =  iFs.GetDir(aDirectory, KEntryAttNormal, ESortNone, aDir);
       
  3141 	return error;
       
  3142 	}
       
  3143 
       
  3144 TInt CMsvServer::AddEntry(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId, TBool aBulk)
       
  3145 	{
       
  3146 
       
  3147 #if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3148 	TDriveUnit defaultDrive(iSystemDrive);
       
  3149 
       
  3150 	// Don't attempt to store the message if the Message Store is being copied
       
  3151 	// from the internal disk to the MMC
       
  3152 	if (iStartupState == EMsvMediaUnavailable)
       
  3153 		{
       
  3154 #ifndef _NO_SERVER_LOGGING_
       
  3155 		Log(_L("CMsvServer::AddEntry - Media is unavailable"));
       
  3156 #endif
       
  3157 
       
  3158 		TInt currentDrive = 0;
       
  3159 		TRAPD(err, currentDrive = MessageServer::CurrentDriveL(iFs));
       
  3160 
       
  3161 		if (err != KErrNone)
       
  3162 			{
       
  3163 			return err;
       
  3164 			}
       
  3165 
       
  3166 		if (currentDrive == defaultDrive)
       
  3167 			{
       
  3168 #ifndef _NO_SERVER_LOGGING_
       
  3169 			Log(_L("Msg store Unavailable, sending KErrNotReady response"));
       
  3170 #endif
       
  3171 			return KErrNotReady;
       
  3172 			}
       
  3173 		}
       
  3174 
       
  3175 	// If we're trying to add something to the Inbox and the disk containing the
       
  3176 	// Message Store is missing, change drive to internal disk
       
  3177 	TInt err = iContext->IndexAdapter()->ErrorState();
       
  3178 	// Assuming the current drive will always be available.
       
  3179 	if (aEntry.iParentId == KMsvGlobalInBoxIndexEntryId && ( err != KErrNone || iStartupState == EMsvMediaUnavailable ) && !iNewContext)
       
  3180 		{
       
  3181 		if(err !=KMsvIndexRestore &&
       
  3182 			err !=KMsvIndexBackup)
       
  3183 			{
       
  3184 #ifndef _NO_SERVER_LOGGING_
       
  3185 			Log(_L("Automatically changing drive to %d"), TInt(defaultDrive));
       
  3186 #endif
       
  3187 			ChangeDrive(TInt(defaultDrive), NULL); // Ignore error?
       
  3188 			}
       
  3189 		}
       
  3190 #endif	  // #if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3191 
       
  3192 	return AddEntry(iContext, aEntry, aOwnerId, aAutoAssignId, aBulk);
       
  3193 	}
       
  3194 
       
  3195 TInt CMsvServer::AddEntry(CMsvIndexContext* const& aContext, TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId, TBool aBulk)
       
  3196 //
       
  3197 // Add a new entry to the Message Store
       
  3198 // Uses the given context
       
  3199 // If aBulk is ETrue,
       
  3200 //	 add entry to bulk selection and update count
       
  3201 //	 based on count, decide whether to commit entry and generate notification
       
  3202 //
       
  3203 	{
       
  3204 	// Return if the message store is not currently available
       
  3205 	TInt err = KErrNone;
       
  3206 	err = aContext->IndexAdapter()->ErrorState();
       
  3207 	if (err != KErrNone)
       
  3208 		return err;
       
  3209 
       
  3210 	// get a unique id for the entry
       
  3211 	if (aAutoAssignId)
       
  3212 		{
       
  3213 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3214 		aEntry.SetId(aContext->IndexAdapter()->NextId(GetDriveId(aEntry.Parent())));
       
  3215 #else
       
  3216 		aEntry.SetId(aContext->IndexAdapter()->NextId());
       
  3217 #endif
       
  3218 		}
       
  3219 
       
  3220 	TInt error = KErrNone;
       
  3221 
       
  3222 	if (aBulk)
       
  3223 		{
       
  3224 		TRAP(error, iBulkCreationSelection->AppendL(aEntry.Id()));
       
  3225 		}
       
  3226 
       
  3227 #ifndef _NO_SERVER_LOGGING_
       
  3228 	Log(_L("Adding entry with id %x"), aEntry.Id());
       
  3229 #endif
       
  3230 
       
  3231 	TFileName fileName;
       
  3232 
       
  3233 	// create the path for a service
       
  3234 	if (aEntry.iType==KUidMsvServiceEntry)
       
  3235 		{
       
  3236 		fileName = aContext->MessageFolder();
       
  3237 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3238 		MsvUtils::ConstructEntryName(UnmaskTMsvId(aEntry.Id()), aEntry.Id(), fileName, MsvUtils::EPath);
       
  3239 #else
       
  3240 		MsvUtils::ConstructEntryName(aEntry.Id(), aEntry.Id(), fileName, MsvUtils::EPath);
       
  3241 #endif
       
  3242 
       
  3243 #ifndef _NO_SERVER_LOGGING_
       
  3244 		Log(_L("Creating path for service %S"), &fileName);
       
  3245 #endif
       
  3246 		error = iFs.MkDir(fileName);
       
  3247 		}
       
  3248 
       
  3249 	// add the entry to the index
       
  3250 	if (error==KErrNone || error==KErrAlreadyExists)
       
  3251 		{
       
  3252 		if (!aBulk)
       
  3253 			{
       
  3254 			error = aContext->IndexAdapter()->AddEntry(aEntry, aOwnerId, EFalse);
       
  3255 			// We may also have a bulk procedure occuring at this time.
       
  3256 			// This call to AddEntry will commit those entries to the index file,
       
  3257 			// so we should let any observers know about the bulk entries now.
       
  3258 			// With the parallel message processing, we will have to forego some of
       
  3259 			// the efficiencies of bulk processing.
       
  3260 			if ((iBulkCreationSelection->Count() != 0) || (iBulkChangeSelection->Count() != 0))
       
  3261 				{
       
  3262 				TRAP(error, NotifyChangedBulkL());
       
  3263 				}
       
  3264 			}
       
  3265 		else
       
  3266 			{
       
  3267 			if (iBulkCreationSelection->Count() == KBulkCommitInterval)
       
  3268 				{
       
  3269 				error = aContext->IndexAdapter()->AddEntry(aEntry, aOwnerId, EFalse);
       
  3270 				// We have done a bulk commit to the index file.
       
  3271 				// Let observers know about the entries
       
  3272 				TRAP(error, NotifyChangedBulkL());
       
  3273 				}
       
  3274 			else
       
  3275 				{
       
  3276 				error = aContext->IndexAdapter()->AddEntryNoCommit(aEntry, aOwnerId, EFalse);
       
  3277 				}
       
  3278 			}
       
  3279 		if (error==KErrNone)
       
  3280 			{
       
  3281 			}
       
  3282 		// Delete the service folder if we created one
       
  3283 		else if ((fileName.Length() > 0) && error!=KErrAlreadyExists)
       
  3284 			iFs.RmDir(fileName);
       
  3285 		}
       
  3286 
       
  3287 	return error;
       
  3288 	}
       
  3289 
       
  3290 
       
  3291 TInt CMsvServer::ChangeEntry(const TMsvEntry& aEntry, TSecureId aOwnerId, TBool aForcedUpdate, TBool aBulk)
       
  3292 //
       
  3293 //
       
  3294 //
       
  3295 	{
       
  3296 #ifndef _NO_SERVER_LOGGING_
       
  3297 	Log(_L("Changing entry with id %x"), aEntry.Id());
       
  3298 #endif
       
  3299 
       
  3300 	TInt error;
       
  3301 	if (!aBulk)
       
  3302 		{
       
  3303 		error = iContext->IndexAdapter()->ChangeEntry(aEntry, aOwnerId, aForcedUpdate);
       
  3304 		// We may also have a bulk procedure occuring at this time.
       
  3305 		// This call to ChangeEntry will commit those entries to the index file,
       
  3306 		// so we should let any observers know about the bulk entries now.
       
  3307 		if ((iBulkCreationSelection->Count() != 0) || (iBulkChangeSelection->Count() != 0))
       
  3308 			{
       
  3309 			TRAP(error, NotifyChangedBulkL());
       
  3310 			}
       
  3311 		}
       
  3312 	else
       
  3313 		{
       
  3314 		TRAP(error, iBulkChangeSelection->AppendL(aEntry.Id()));
       
  3315 		if (error == KErrNone)
       
  3316 			{
       
  3317 			if (iBulkChangeSelection->Count() == KBulkCommitInterval)
       
  3318 				{
       
  3319 				error = iContext->IndexAdapter()->ChangeEntry(aEntry, aOwnerId, aForcedUpdate);
       
  3320 				// We have done a bulk commit to the index file. Let observers know about the entries.
       
  3321 				TRAP(error, NotifyChangedBulkL());
       
  3322 				}
       
  3323 			else
       
  3324 				{
       
  3325 				error = iContext->IndexAdapter()->ChangeEntryNoCommit(aEntry, aOwnerId, aForcedUpdate);
       
  3326 				}
       
  3327 			}
       
  3328 		}
       
  3329 
       
  3330 	return error;
       
  3331 	}
       
  3332 
       
  3333 
       
  3334 
       
  3335 TInt CMsvServer::CheckMtmStatus(TMsvId aServiceId, TBool& aRunning)
       
  3336 //
       
  3337 // Returns
       
  3338 //  KErrNotFound if the mtm is not loaded
       
  3339 //  >=0 if the mtm is loaded and this is the position in the queue array
       
  3340 //  aRunning is true if an operation is currently running
       
  3341 //
       
  3342 	{
       
  3343 	aRunning = EFalse;
       
  3344 	TInt count=iMtmOperationQueueArray.Count();
       
  3345 	while (count--)
       
  3346 		{
       
  3347 		// check if the service has a loaded mtm
       
  3348 		if (iMtmOperationQueueArray.At(count)->ServiceId() == aServiceId)
       
  3349 			{
       
  3350 			aRunning = iMtmOperationQueueArray.At(count)->Count()!=0;
       
  3351 			return count;
       
  3352 			}
       
  3353 		}
       
  3354 	return KErrNotFound;
       
  3355 	}
       
  3356 
       
  3357 #ifdef MSG_SERV_AUTO_CLOSE
       
  3358 void CMsvServer::CheckAndClose()
       
  3359 	{
       
  3360 	// check if any session remaining are just observers - then shut down
       
  3361 
       
  3362 	iSessionIter.SetToFirst();
       
  3363 
       
  3364 	if(iBackup && iBackup->Locked()!=EFalse)
       
  3365 		{
       
  3366 #ifndef _NO_SERVER_LOGGING_
       
  3367 		Log(_L("Not closing sever because we have a backup lock to retake."));
       
  3368 #endif
       
  3369 		}
       
  3370 	else if(iMailinitWaiter->IsActive())
       
  3371 		{
       
  3372 #ifndef _NO_SERVER_LOGGING_
       
  3373 		Log(_L("Not closing sever because we are waiting for mailinit to finish"));
       
  3374 #endif  //_NO_SERVER_LOGGING_
       
  3375 		}
       
  3376 	else if (iSessionIter == NULL)
       
  3377 		{
       
  3378 
       
  3379 		if (iCloseServer)
       
  3380 			{
       
  3381 			CActiveScheduler::Stop();
       
  3382 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3383 			MailinitFinished(KErrNone, iDriveList->CurrentDriveNumber());
       
  3384 #else
       
  3385 			MailinitFinished(KErrNone, (TDriveNumber) (TInt)(iContext->Config().iDrive));
       
  3386 #endif
       
  3387 			}
       
  3388 		else
       
  3389 			{
       
  3390 			iCloseTimer->Cancel();
       
  3391 			iCloseTimer->After(KMsvCloseTime);
       
  3392 			}
       
  3393 		}
       
  3394 	else if (!iCloseServer)
       
  3395 		{
       
  3396 		TBool shouldClose=ETrue;
       
  3397 
       
  3398 		iSessionIter.SetToFirst();
       
  3399 		CMsvServerSession* session = (CMsvServerSession*)&(*iSessionIter++);
       
  3400 		while(session)
       
  3401 			{
       
  3402 			if (!session->IsAnObserver())
       
  3403 				{
       
  3404 				shouldClose=EFalse;
       
  3405 				break;
       
  3406 				}
       
  3407 			session = (CMsvServerSession*)&(*iSessionIter++);
       
  3408 			}
       
  3409 
       
  3410 		if (shouldClose)
       
  3411 			{
       
  3412 #ifndef _NO_SERVER_LOGGING_
       
  3413 			Log(_L("Telling clients to close - CheckAndClose"));
       
  3414 #endif
       
  3415 			NotifyChanged(EMsvCloseSession, KMsvNullIndexEntryId);
       
  3416 			iCloseServer=ETrue;
       
  3417 			}
       
  3418 		}
       
  3419 	}
       
  3420 #endif	  // MSG_SERV_AUTO_CLOSE
       
  3421 
       
  3422 
       
  3423 void CMsvServer::ClosingSession(TInt aSessionId)
       
  3424 //
       
  3425 // Ensures that no mtm are left running when a session is closed
       
  3426 // NOTE Cannot leave - called by CMsvServerSession d'tor
       
  3427 //
       
  3428 	{
       
  3429 	TInt ii = iMtmOperationQueueArray.Count();
       
  3430 	// check each queue
       
  3431 	while (ii--)
       
  3432 		{
       
  3433 		// check if the session used this queue
       
  3434 		CMsvMtmOperationQueue* queue = iMtmOperationQueueArray.At(ii);
       
  3435 		TInt jj = queue->iSessionIdArray.Count();
       
  3436 		while (jj--)
       
  3437 			{
       
  3438 			if (queue != NULL && queue->iSessionIdArray.At(jj)==aSessionId)
       
  3439 				{
       
  3440 				// the session used this queue - so remove the reference to it
       
  3441 				queue->iSessionIdArray.Delete(jj);
       
  3442 
       
  3443 #if defined(_DEBUG)
       
  3444 				// check all session operations have been removed
       
  3445 				TInt kk = queue->Count();
       
  3446 				while (kk--)
       
  3447 					__ASSERT_DEBUG(queue->At(kk)->SessionId()!=aSessionId, PanicServer(EMsvOutstandingOperation));
       
  3448 #endif
       
  3449 				// check if anyone else is using the queue
       
  3450 				if (queue->iSessionIdArray.Count()==0)
       
  3451 					{
       
  3452 					// remove the mtm and queue
       
  3453 					delete queue;
       
  3454 					queue = NULL;
       
  3455 					iMtmOperationQueueArray.Delete(ii);
       
  3456 					}
       
  3457 				}
       
  3458 			}
       
  3459 		}
       
  3460 
       
  3461 	iSessionIter.SetToFirst();
       
  3462 	iSessionIter++;
       
  3463 
       
  3464 	if (iSessionIter == NULL)
       
  3465 		{
       
  3466 		if (iCloseServer)
       
  3467 			{
       
  3468 			CActiveScheduler::Stop();
       
  3469 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3470 			MailinitFinished(KErrNone, iDriveList->CurrentDriveNumber());
       
  3471 #else
       
  3472 			MailinitFinished(KErrNone, (TDriveNumber) (TInt)(iContext->Config().iDrive));
       
  3473 #endif
       
  3474 			}
       
  3475 
       
  3476 #ifdef MSG_SERV_AUTO_CLOSE
       
  3477 		else
       
  3478 			{
       
  3479 			iCloseTimer->Cancel();
       
  3480 			iCloseTimer->After(KMsvCloseTime);
       
  3481 			}
       
  3482 
       
  3483 		}
       
  3484 	else if (!iCloseServer)
       
  3485 		{
       
  3486 		// check if any session remaining are just observers - then shut down
       
  3487 		TBool shouldClose=ETrue;
       
  3488 
       
  3489 		iSessionIter.SetToFirst();
       
  3490 		CMsvServerSession* session = (CMsvServerSession*)&(*iSessionIter++);
       
  3491 		while(session)
       
  3492 			{
       
  3493 			if (!session->IsAnObserver() && session->SessionId() != aSessionId)
       
  3494 				{
       
  3495 				shouldClose=EFalse;
       
  3496 				break;
       
  3497 				}
       
  3498 			session = (CMsvServerSession*)&(*iSessionIter++);
       
  3499 			}
       
  3500 
       
  3501 		if (shouldClose)
       
  3502 			{
       
  3503 #ifndef _NO_SERVER_LOGGING_
       
  3504 			Log(_L("Telling clients to close - Closing session"));
       
  3505 #endif
       
  3506 			NotifyChanged(EMsvCloseSession, KMsvNullIndexEntryId);
       
  3507 			iCloseServer=ETrue;
       
  3508 			}
       
  3509 #endif
       
  3510 
       
  3511 		}
       
  3512 
       
  3513 	}
       
  3514 
       
  3515 
       
  3516 TBool CMsvServer::SessionIdInQueue(CMsvMtmOperationQueue& aQueue, TInt aSessionId) const
       
  3517 //
       
  3518 // Returns true if the session id is already in the queue session id array
       
  3519 //
       
  3520 	{
       
  3521 	TInt count=aQueue.iSessionIdArray.Count();
       
  3522 	while (count--)
       
  3523 		{
       
  3524 		if (aQueue.iSessionIdArray.At(count)==aSessionId)
       
  3525 			return ETrue;
       
  3526 		}
       
  3527 	return EFalse;
       
  3528 	}
       
  3529 
       
  3530 void CMsvServer::QueueOperationL(CMsvMtmOperation& aOperation, TInt aSessionId)
       
  3531 //
       
  3532 // Appends an operation to the correct mtm queue
       
  3533 //
       
  3534 	{
       
  3535 	// append the operation on the right queue
       
  3536 	TInt count=iMtmOperationQueueArray.Count();
       
  3537 	while (count--)
       
  3538 		{
       
  3539 		if (iMtmOperationQueueArray.At(count)->ServiceId() == aOperation.ServiceId())
       
  3540 			{
       
  3541 			AddSessionIdToQueueL(*iMtmOperationQueueArray.At(count), aSessionId);
       
  3542 			iMtmOperationQueueArray.At(count)->AppendL(&aOperation);
       
  3543 			aOperation.SetState(EMsvOperationQueued);
       
  3544 
       
  3545 			}
       
  3546 		}
       
  3547 	__ASSERT_DEBUG(aOperation.State() == EMsvOperationQueued, PanicServer(EMsvOperationQueueNotFound1));
       
  3548 	}
       
  3549 
       
  3550 
       
  3551 void CMsvServer::StartOperationL(CMsvMtmOperation& aOperation, TInt aSessionId, const RMessage2 &aMessage, TBool hasCapability)
       
  3552 //
       
  3553 // Either starts an operation or queues it for later execution
       
  3554 //
       
  3555 	{
       
  3556 	// check the mtm exists
       
  3557 	if (!iServerMtmReg->IsPresent(aOperation.MtmUid()))
       
  3558 		User::Leave(KErrNotFound);
       
  3559 
       
  3560 	// get the status of the service mtm
       
  3561 	TBool opRunning;
       
  3562 	TInt index = CheckMtmStatus(aOperation.ServiceId(), opRunning);
       
  3563 
       
  3564 	// if an operation is already running, queue this one
       
  3565 	if (opRunning)
       
  3566 		{
       
  3567 		QueueOperationL(aOperation, aSessionId);
       
  3568 		return;
       
  3569 		}
       
  3570 
       
  3571 	// create the new mtm if required
       
  3572 	CMsvMtmOperationQueue* queue;
       
  3573 	if (index==KErrNotFound)
       
  3574 		{
       
  3575 		queue = new(ELeave) CMsvMtmOperationQueue(aOperation.MtmUid(), aOperation.ServiceId());
       
  3576 		CleanupStack::PushL(queue);
       
  3577 
       
  3578 		// load the mtm and assign to the queue
       
  3579 		queue->iMtm = LoadMtmL(aOperation);
       
  3580 
       
  3581 		// append the operation to the queue
       
  3582 		queue->AppendL(&aOperation);
       
  3583 
       
  3584 		iMtmOperationQueueArray.AppendL(queue);
       
  3585 		CleanupStack::Pop(); // queue
       
  3586 		}
       
  3587 	else
       
  3588 		{
       
  3589 		queue = iMtmOperationQueueArray.At(index);
       
  3590 		queue->AppendL(&aOperation);
       
  3591 		}
       
  3592 	AddSessionIdToQueueL(*queue, aSessionId);
       
  3593 #if (defined SYMBIAN_USER_PROMPT_SERVICE)   
       
  3594 	RThread thread;
       
  3595 	User::LeaveIfError(aMessage.Client(thread));
       
  3596 	TThreadId threadId = thread.Id();
       
  3597 	aOperation.SetThreadId(threadId);
       
  3598 	thread.Close();
       
  3599 #else
       
  3600 	if(aMessage.IsNull()){} // To avoid compiler warnings
       
  3601 #endif
       
  3602 	// start the operation
       
  3603 	aOperation.Start(*queue->iMtm, hasCapability);
       
  3604 	aOperation.SetState(EMsvOperationRunning);
       
  3605 	}
       
  3606 
       
  3607 
       
  3608 
       
  3609 CBaseServerMtm* CMsvServer::LoadMtmL(const CMsvMtmOperation& aOperation)
       
  3610 //
       
  3611 // Returns the server mtm instance required for the operation
       
  3612 //
       
  3613 	{
       
  3614 	CBaseServerMtm* mtm = iServerMtmReg->NewServerMtmL(aOperation.MtmUid(), CMsvServerEntry::NewL(*this, aOperation.ServiceId()));
       
  3615 	return mtm;
       
  3616 	}
       
  3617 
       
  3618 
       
  3619 
       
  3620 #if defined(_DEBUG)
       
  3621 void CMsvServer::OperationCompleted(TMsvId aServiceId, TMsvOp aOpId)
       
  3622 #else
       
  3623 void CMsvServer::OperationCompleted(TMsvId aServiceId, TMsvOp /*aOpId*/)
       
  3624 #endif
       
  3625 //
       
  3626 // An operation has completed, so start the next operation if there is one or remove the Mtm
       
  3627 //
       
  3628 	{
       
  3629 	// find the correct operation queue
       
  3630 	CMsvMtmOperationQueue* queue=NULL;
       
  3631 	TInt count=iMtmOperationQueueArray.Count();
       
  3632 	while (count--)
       
  3633 		{
       
  3634 		if (iMtmOperationQueueArray.At(count)->ServiceId() == aServiceId)
       
  3635 			{
       
  3636 			queue = iMtmOperationQueueArray.At(count);
       
  3637 			break;
       
  3638 			}
       
  3639 		}
       
  3640 	__ASSERT_DEBUG(count>=0, PanicServer(EMsvOperationQueueNotFound2));
       
  3641 
       
  3642 	if ( queue != NULL )
       
  3643 		{
       
  3644 		__ASSERT_DEBUG(queue->At(0)->Id()==aOpId, PanicServer(EMsvWrongOperationCompletion));
       
  3645 
       
  3646 		// mark the operation as completed and remove from the queue
       
  3647 		queue->At(0)->SetState(EMsvOperationCompleted);
       
  3648 		queue->Delete(0);
       
  3649 
       
  3650 		// start the next operation
       
  3651 		StartNextOperation(queue, count);
       
  3652 		}
       
  3653 	}
       
  3654 
       
  3655 TInt CMsvServer::OutstandingOperations()
       
  3656 	{
       
  3657 	TInt count = 0;
       
  3658 	iSessionIter.SetToFirst();
       
  3659 	CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3660 	while (ses!=NULL)
       
  3661 		{
       
  3662 		count += ses->HaveOutstandingOperations();
       
  3663 		ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3664 		}
       
  3665 	return count;
       
  3666 	}
       
  3667 
       
  3668 void CMsvServer::OperationCancelled(const CMsvMtmOperation& aOperation)
       
  3669 //
       
  3670 // An operation has cancelled
       
  3671 //
       
  3672 	{
       
  3673 	const TMsvId aServiceId = aOperation.ServiceId();
       
  3674 
       
  3675 	// find the correct operation queue
       
  3676 	CMsvMtmOperationQueue* queue=NULL;
       
  3677 	TInt qCount=iMtmOperationQueueArray.Count();
       
  3678 	while (qCount--)
       
  3679 		{
       
  3680 		if (iMtmOperationQueueArray.At(qCount)->ServiceId() == aServiceId)
       
  3681 			{
       
  3682 			queue = iMtmOperationQueueArray.At(qCount);
       
  3683 			break;
       
  3684 			}
       
  3685 		}
       
  3686 	__ASSERT_DEBUG(qCount>=0, PanicServer(EMsvOperationQueueNotFound3));
       
  3687 
       
  3688 	// find the correct operation
       
  3689 	if (queue != NULL)
       
  3690 		{
       
  3691 		TInt oCount=queue->Count();
       
  3692 		while (oCount--)
       
  3693 			{
       
  3694 			if (queue->At(oCount) == &aOperation)
       
  3695 				break;
       
  3696 			}
       
  3697 		__ASSERT_DEBUG(oCount>=0, PanicServer(EMsvOperationNotFound));
       
  3698 		__ASSERT_DEBUG(queue->At(oCount)->State()==EMsvOperationQueued, PanicServer(EMsvCancelledNonQueueOp));
       
  3699 		if (oCount>=0)
       
  3700 			queue->Delete(oCount);
       
  3701 		}
       
  3702 	}
       
  3703 
       
  3704 
       
  3705 
       
  3706 void CMsvServer::StartNextOperation(CMsvMtmOperationQueue* aQueue, TInt aQueueIndex)
       
  3707 //
       
  3708 //
       
  3709 //
       
  3710 	{
       
  3711 	// if there are no more operations
       
  3712 	if (aQueue->Count()==0)
       
  3713 		{
       
  3714 		if (!aQueue->iMtm->CommandExpected())
       
  3715 			{
       
  3716 			// the mtm is no longer needed
       
  3717 			delete iMtmOperationQueueArray.At(aQueueIndex);
       
  3718 			iMtmOperationQueueArray.Delete(aQueueIndex);
       
  3719 			}
       
  3720 		return;
       
  3721 		}
       
  3722 
       
  3723 
       
  3724 	// if the Mtm cannot accept multiple commands, create a new one
       
  3725 	if (!aQueue->iMtm->CommandExpected())
       
  3726 		{
       
  3727 		delete aQueue->iMtm;
       
  3728 		aQueue->iMtm=NULL;
       
  3729 		TRAPD(leave, {aQueue->iMtm = LoadMtmL(*aQueue->At(0));});
       
  3730 		if (leave)
       
  3731 			{
       
  3732 			// fail all queued operations
       
  3733 			TInt count=aQueue->Count();
       
  3734 			while (count--)
       
  3735 				{
       
  3736 				aQueue->At(count)->Failed(leave);
       
  3737 				aQueue->Delete(count);
       
  3738 				}
       
  3739 			// delete the mtm queue
       
  3740 			delete iMtmOperationQueueArray.At(aQueueIndex);
       
  3741 			iMtmOperationQueueArray.Delete(aQueueIndex);
       
  3742 			return;
       
  3743 			}
       
  3744 		}
       
  3745 	aQueue->At(0)->Start(*aQueue->iMtm, EFalse);
       
  3746 	aQueue->At(0)->SetState(EMsvOperationRunning);
       
  3747 	}
       
  3748 
       
  3749 
       
  3750 TInt CMsvServer::FillRegisteredMtmDllArray(TUid aMtmDllTypeUid,CRegisteredMtmDllArray& aRegisteredMtmDllArray)
       
  3751 	{
       
  3752 	return iMtmRegControl->FillRegisteredMtmDllArray(aMtmDllTypeUid,aRegisteredMtmDllArray);
       
  3753 	}
       
  3754 
       
  3755 
       
  3756 TInt CMsvServer::InstallMtmGroup(const TDesC& aFullName,TUid& aMtmTypeUid)
       
  3757 	{
       
  3758 	TInt error=iMtmRegControl->InstallMtmGroup(aFullName,aMtmTypeUid);
       
  3759 	return error;
       
  3760 	}
       
  3761 
       
  3762 
       
  3763 TInt CMsvServer::DeInstallMtmGroup(const TDesC& aFullName,TUid& aMtmTypeUid)
       
  3764 	{
       
  3765 	TInt error=iMtmRegControl->FullNameToMtmTypeUid(aFullName,aMtmTypeUid);
       
  3766 	if (error==KErrNone)
       
  3767 		{
       
  3768 		TBool isinuse=iMtmRegControl->IsInUse(aMtmTypeUid);
       
  3769 		if (!isinuse)
       
  3770 			{
       
  3771 			iSessionIter.SetToFirst();
       
  3772 			CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3773 			while ((ses!=NULL) && !isinuse)
       
  3774 				{
       
  3775 				isinuse=ses->IsInUse(aMtmTypeUid);
       
  3776 				ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3777 				}
       
  3778 			}
       
  3779 		if (isinuse)
       
  3780 			error=KErrInUse;
       
  3781 		}
       
  3782 	if (error==KErrNone)
       
  3783 		error=iMtmRegControl->DeInstallMtmGroup(aMtmTypeUid);
       
  3784 	return error;
       
  3785 	}
       
  3786 
       
  3787 
       
  3788 CMtmGroupData* CMsvServer::GetMtmGroupDataL(TUid aMtmTypeUid) const
       
  3789 	{
       
  3790 	return iMtmRegControl->GetMtmGroupDataL(aMtmTypeUid);
       
  3791 	}
       
  3792 
       
  3793 
       
  3794 void CMsvServer::GetMtmRequiredCapabilitiesL(TUid aMtmTypeUid, TCapabilitySet& aCaps) const
       
  3795 	{
       
  3796 	aCaps=iMtmRegControl->GetMtmGroupDataReferenceL(aMtmTypeUid).GetMtmRequiredCapabilities();
       
  3797 	}
       
  3798 
       
  3799 
       
  3800 void CMsvServer::StopServiceL(const RMessage2& aMessage)
       
  3801 //
       
  3802 // Stops a service by cancelling all operations and deleting the server MTM
       
  3803 //
       
  3804 	{
       
  3805 	TMsvId serviceId = aMessage.Int0();
       
  3806 	TBool active;
       
  3807 	TInt index = CheckMtmStatus(serviceId, active);
       
  3808 
       
  3809 	// service MTM is not loaded
       
  3810 	if (index==KErrNotFound)
       
  3811 		{
       
  3812 		aMessage.Complete(KErrNotFound);
       
  3813 		return;
       
  3814 		}
       
  3815 
       
  3816 	// The service MTM is loaded - police if the client can stop it.
       
  3817 	PoliceStopServiceL(aMessage, iMtmOperationQueueArray.At(index)->MtmUid(), __PLATSEC_DIAGNOSTIC_STRING("Checked by CMsvServer::StopService"));
       
  3818 
       
  3819 	// get all sessions to cancel/stop the operations
       
  3820 	iSessionIter.SetToFirst();
       
  3821 	CMsvServerSession* ses = (CMsvServerSession*)&(*iSessionIter++);
       
  3822 	while (ses!=NULL)
       
  3823 		{
       
  3824 		ses->StopOperations(serviceId);
       
  3825 		ses = (CMsvServerSession*)&(*(iSessionIter++));
       
  3826 		}
       
  3827 
       
  3828 	// check if the server MTM has been persisted
       
  3829 	index = CheckMtmStatus(serviceId, active);
       
  3830 	// remove the queue - irrespective of request of the Server MTM
       
  3831 	if (index!=KErrNotFound)
       
  3832 		{
       
  3833 		delete iMtmOperationQueueArray.At(index);
       
  3834 		iMtmOperationQueueArray.Delete(index);
       
  3835 		}
       
  3836 	aMessage.Complete(KErrNone);
       
  3837 	}
       
  3838 
       
  3839 
       
  3840 
       
  3841 void CMsvServer::ServiceActive(const RMessage2& aMessage)
       
  3842 //
       
  3843 // Completes ETrue if the server MTM is running an operation
       
  3844 //
       
  3845 	{
       
  3846 	TMsvId serviceId = aMessage.Int0();
       
  3847 	TBool active;
       
  3848 	CheckMtmStatus(serviceId, active); // error ignored as "active" is always set correctly
       
  3849 	aMessage.Complete(active);
       
  3850 	}
       
  3851 
       
  3852 
       
  3853 
       
  3854 const TDesC8& CMsvServer::ServiceProgressL(TMsvId aServcieId)
       
  3855 //
       
  3856 // Returns the progress from the server MTM
       
  3857 //
       
  3858 	{
       
  3859 	TBool active;
       
  3860 	TInt index = CheckMtmStatus(aServcieId, active);
       
  3861 
       
  3862 	// service MTM is not loaded
       
  3863 	if (index==KErrNotFound)
       
  3864 		User::Leave(KErrNotFound);
       
  3865 
       
  3866 	// get the progress from the server MTM
       
  3867 	CMsvMtmOperationQueue* queue = iMtmOperationQueueArray.At(index);
       
  3868 	return queue->iMtm->Progress();
       
  3869 	}
       
  3870 
       
  3871 
       
  3872 void CMsvServer::AttemptDelayedUpdating()
       
  3873 //
       
  3874 //
       
  3875 //
       
  3876 	{
       
  3877 	if (iContext)
       
  3878 		{
       
  3879 		if(iContext->Initialized()==EFalse)
       
  3880 			{
       
  3881 			iContext->Initialized(ETrue);
       
  3882 			TRAP_IGNORE({iContext->LocalizeStandardFoldersL();
       
  3883 							SuspendSendingMessagesL();});
       
  3884 			}
       
  3885 
       
  3886 		if (iContext->Remove().Count())
       
  3887 			RemoveEntry(KMsvNullIndexEntryId);
       
  3888 
       
  3889 		if (iContext->Update().Count() && !iDelayTimer->IsActive())
       
  3890 			iDelayTimer->After(KMsvDelayTime);
       
  3891 		}
       
  3892 	}
       
  3893 
       
  3894 
       
  3895 
       
  3896 
       
  3897 // this cleans up messages left sending when the machine was
       
  3898 // rebooted, as they would otherwise be displayed to the user
       
  3899 // as sending when they aren't
       
  3900 // A better fix would be to allow the server mtms to clean up
       
  3901 // on startup, then they could attempt to continue sending the
       
  3902 // message.
       
  3903 // This also only copes with mtms that either use the KMsvSendStateSending and KMsvSendStateWaiting
       
  3904 // or the fax mtm because I know about those.
       
  3905 
       
  3906 // copied from fxut.h included so that we can set things with fax sending states
       
  3907 // to suspended on message server start
       
  3908 // horrible but we don't want to have to have fax available to build the message
       
  3909 // server.
       
  3910 enum TFaxSendingState
       
  3911 	{
       
  3912 	EFaxSendingStateCalling = (KMsvSendStateLast + 1),
       
  3913 		EFaxSendingStateNegotiating,
       
  3914 		EFaxSendingStatePreparing
       
  3915 	};
       
  3916 // can't find a header that defines this (it is defined in FXSENDOP.CPP
       
  3917 // and FAXC.CPP but I don't want to move it into a header now.
       
  3918 const TUid KUidMsgTypeFax = {0x1000102B};
       
  3919 
       
  3920 void CMsvServer::SuspendSendingMessagesL()
       
  3921 	{
       
  3922 	CMsvEntrySelection *selection=new(ELeave)CMsvEntrySelection;
       
  3923 	CleanupStack::PushL(selection);
       
  3924 	CMsvEntryFilter *filter=CMsvEntryFilter::NewLC();
       
  3925 	
       
  3926 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3927 		User::LeaveIfError(iContext->IndexAdapter()->GetChildrenIdAll(KMsvGlobalOutBoxIndexEntryId,*filter,*selection));
       
  3928 #else
       
  3929 		User::LeaveIfError(iContext->IndexAdapter()->GetChildrenId(KMsvGlobalOutBoxIndexEntryId,*filter,*selection));
       
  3930 #endif
       
  3931 
       
  3932 	TInt count=selection->Count();
       
  3933 	while(count--)
       
  3934 		{
       
  3935 		TMsvEntry *entry;
       
  3936 		TInt err = KErrNone;
       
  3937 		err = iContext->IndexAdapter()->GetEntry(selection->At(count),entry);
       
  3938 		if(err == KErrNone)
       
  3939 			{
       
  3940 			const TUint sendingState=entry->SendingState();
       
  3941 
       
  3942 			if(sendingState==KMsvSendStateSending ||
       
  3943 			   sendingState==KMsvSendStateWaiting ||
       
  3944 				(entry->iMtm==KUidMsgTypeFax && (sendingState== EFaxSendingStateCalling ||
       
  3945 												 sendingState== EFaxSendingStateNegotiating ||
       
  3946 												 sendingState== EFaxSendingStatePreparing)))
       
  3947 				{
       
  3948 				entry->SetSendingState(KMsvSendStateSuspended);
       
  3949 				// ignore error as we can't report it and want to try fixing
       
  3950 				// the next entry in the list.
       
  3951 				iContext->IndexAdapter()->ChangeEntry(*entry, KMsvServerId, EFalse);
       
  3952 				}
       
  3953 			}
       
  3954 		}
       
  3955 	CleanupStack::PopAndDestroy(2,selection); //filter, selection
       
  3956 	}
       
  3957 
       
  3958 void CMsvServer::RemoveEntry(TMsvId aId)
       
  3959 //
       
  3960 // Removes the removed entries from the index. Client were not interested in result.
       
  3961 //
       
  3962 	{
       
  3963 #ifndef _NO_SERVER_LOGGING_
       
  3964 	TRAPD(leave, DoRemoveEntriesL(aId));
       
  3965 	Log(_L("Remove entry %x, error %d, list size %d"), aId, leave, iContext->Remove().Count());
       
  3966 #else
       
  3967 	TRAP_IGNORE(DoRemoveEntriesL(aId));
       
  3968 #endif
       
  3969 
       
  3970 	// start the timer if entries are stil requiring removal and the timer isn't running
       
  3971 	if (iContext->Remove().Count() && !iDelayTimer->IsActive())
       
  3972 		iDelayTimer->After(KMsvDelayTime);
       
  3973 	}
       
  3974 
       
  3975 void CMsvServer::DoRemoveEntriesL(TMsvId aId)
       
  3976 //
       
  3977 // Deletes the removed entries from the index. Client were not interested in result.
       
  3978 //
       
  3979 	{
       
  3980 	if (aId!=KMsvNullIndexEntryId)
       
  3981 		{
       
  3982 		iContext->Remove().AppendL(aId);
       
  3983 		iContext->Remove().SetReserveL(iContext->Remove().Count()+1);
       
  3984 		}
       
  3985 	else if (iContext->Remove().Count()==0)
       
  3986 		return;
       
  3987 
       
  3988 	CMsvEntrySelection* deletedSelection = new(ELeave) CMsvEntrySelection;
       
  3989 	CleanupStack::PushL(deletedSelection);
       
  3990 	CMsvEntrySelection* movedSelection = new(ELeave) CMsvEntrySelection;
       
  3991 	CleanupStack::PushL(movedSelection);
       
  3992 	CMsvDelete* deleteEntry = CMsvDelete::NewL(*this);
       
  3993 	CleanupStack::PushL(deleteEntry);
       
  3994 
       
  3995 	TInt count=iContext->Remove().Count();
       
  3996 	while (count--)
       
  3997 		{
       
  3998 		// find the parent
       
  3999 		TMsvEntry* entry;
       
  4000 		TInt error = KErrNone;
       
  4001 		error = iContext->IndexAdapter()->GetEntry(iContext->Remove().At(count), entry);
       
  4002 		if (error)
       
  4003 			continue;
       
  4004 
       
  4005 		// delete the entry
       
  4006 		TMsvId parent = entry->Parent();
       
  4007 
       
  4008 		// Note: It should be possible to get rid of this trap - but this is safer for now
       
  4009 		TRAP(error, deleteEntry->StartL(entry->Id(), *deletedSelection, *movedSelection));
       
  4010 		if (error == KErrNone)
       
  4011 			{
       
  4012 			// notify client of a deletion
       
  4013 			iContext->Remove().Delete(count);
       
  4014 			if (deletedSelection->Count())
       
  4015 				NotifyChanged(EMsvEntriesDeleted, *deletedSelection, parent);
       
  4016 			if (movedSelection->Count())
       
  4017 				{
       
  4018 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4019 				NotifyChanged(EMsvEntriesMoved, *movedSelection, MaskTMsvId(GetDriveId(aId), KMsvDeletedEntryFolderEntryId), parent);
       
  4020 #else
       
  4021 				NotifyChanged(EMsvEntriesMoved, *movedSelection, KMsvDeletedEntryFolderEntryId, parent);
       
  4022 #endif
       
  4023 				}
       
  4024 			}
       
  4025 
       
  4026 		deletedSelection->Reset();
       
  4027 		movedSelection->Reset();
       
  4028 		}
       
  4029 
       
  4030 	CleanupStack::PopAndDestroy(3); // moveSelection, deletedSelection, deleteentry
       
  4031 	}
       
  4032 
       
  4033 
       
  4034 void CMsvServer::CloseServer(const RMessage2& aMessage)
       
  4035 //
       
  4036 // Tells alls sessions to close, and when all are closed the server is shut down immediately
       
  4037 //
       
  4038 	{
       
  4039 #ifndef _NO_SERVER_LOGGING_
       
  4040 	Log(_L("Telling clients to close - close server function"));
       
  4041 #endif
       
  4042 	aMessage.Complete(KErrNone);
       
  4043 	NotifyChanged(EMsvCloseSession, KMsvNullIndexEntryId);
       
  4044 	iCloseServer=ETrue;
       
  4045 	}
       
  4046 
       
  4047 
       
  4048 TInt CMsvServer::CheckEntries(const CMsvEntrySelection& aEntries, TInt aStartIndex, TInt aEndIndex)
       
  4049 //
       
  4050 // Checks that all entries in the selection can be deleted, copied, moved etc
       
  4051 //
       
  4052 	{
       
  4053 	for (TInt index=aStartIndex; index<=aEndIndex; index++)
       
  4054 		{
       
  4055 		TMsvId id = aEntries.At(index);
       
  4056 		TBool locked;
       
  4057 		TInt error = KErrNone;
       
  4058 		error = iContext->IndexAdapter()->IsEntryOrStoreLocked(id, locked);
       
  4059 		if (error)
       
  4060 			return error;
       
  4061 		if (locked)
       
  4062 			return KErrAccessDenied;
       
  4063 
       
  4064 		// get the entry
       
  4065 		TMsvEntry* entry;
       
  4066 		iContext->IndexAdapter()->GetEntry(id, entry); // error ignored, as will not fail
       
  4067 		// check the store
       
  4068 		TFileName filename;
       
  4069 		GetEntryName(id, filename, EFalse);
       
  4070 		TBool open;
       
  4071 		error = iFs.IsFileOpen(filename, open);
       
  4072 		if (error)
       
  4073 			{
       
  4074 			if (error!=KErrNotFound && error!=KErrPathNotFound)
       
  4075 				return error;
       
  4076 			}
       
  4077 		else if (open)
       
  4078 			return KErrInUse;
       
  4079 
       
  4080 		// check any files
       
  4081 		CDir* dir;
       
  4082 		error = GetFileDirectoryListing(id, filename, dir);
       
  4083 		if (error == KErrNone)
       
  4084 			{
       
  4085 			error = iFs.SetSessionPath(filename);
       
  4086 			if (error==KErrNone)
       
  4087 				{
       
  4088 				TInt fCount = dir->Count();
       
  4089 				while (fCount--)
       
  4090 					{
       
  4091 					TBool open;
       
  4092 					error = iFs.IsFileOpen((*dir)[fCount].iName, open);
       
  4093 					if (error)
       
  4094 						{
       
  4095 						if (error!=KErrNotFound && error!=KErrPathNotFound)
       
  4096 							{
       
  4097 							delete dir;
       
  4098 							return error;
       
  4099 							}
       
  4100 						}
       
  4101 					else if (open)
       
  4102 						{
       
  4103 						delete dir;
       
  4104 						return KErrInUse;
       
  4105 						}
       
  4106 					}
       
  4107 				}
       
  4108 			delete dir;
       
  4109 			if (error)
       
  4110 				return error;
       
  4111 			}
       
  4112 		else if (error != KErrPathNotFound)
       
  4113 			return error;
       
  4114 		}
       
  4115 	return KErrNone;
       
  4116 	}
       
  4117 
       
  4118 
       
  4119 #ifndef _NO_SERVER_LOGGING_
       
  4120 void CMsvServer::CreateLogL()
       
  4121 	{
       
  4122 	// Connect to flogger
       
  4123 	if (iLog.Connect() == KErrNone)
       
  4124 		{
       
  4125 		iLog.CreateLog(_L("msgs"), _L("server.txt"), EFileLoggingModeOverwrite);
       
  4126 		iLog.SetDateAndTime(EFalse, ETrue);
       
  4127 
       
  4128 		TTime date;
       
  4129 		date.UniversalTime();
       
  4130 
       
  4131 		TBuf<32> dateString;
       
  4132 		date.FormatL(dateString,(_L("%D%M%Y%/0%1%/1%2%/2%3%/3")));
       
  4133 
       
  4134 		TPtrC ver(MessageServer::Version().Name());
       
  4135 		Log(_L("Started message server, date %S, version %S"), &dateString, &ver);
       
  4136 		}
       
  4137 	}
       
  4138 
       
  4139 void CMsvServer::Log(TRefByValue<const TDesC> aFmt, ...)
       
  4140 	{
       
  4141 	if (!iLog.LogValid())
       
  4142 		return;
       
  4143 
       
  4144 	VA_LIST list;
       
  4145 	VA_START(list, aFmt);
       
  4146 
       
  4147 	TBuf<256> buf;
       
  4148 	buf.FormatList(aFmt, list);
       
  4149 
       
  4150 	// Write to log
       
  4151 	iLog.Write(buf);
       
  4152 
       
  4153 #ifndef _NO_SERVER_LOGGING_SERIAL_
       
  4154 	// Write to serial
       
  4155 	_LIT(KFormatSerial, "MSGS: %S");
       
  4156 	RDebug::Print(KFormatSerial, &buf);
       
  4157 #endif
       
  4158 	}
       
  4159 #endif	  // #ifndef _NO_SERVER_LOGGING_
       
  4160 
       
  4161 
       
  4162 
       
  4163 void CMsvServer::SetFailure(TMsvFailure aType, TInt aArg1, TInt aArg2, TInt)
       
  4164 	{
       
  4165 	switch (aType)
       
  4166 		{
       
  4167 		case EHeapFailure:
       
  4168 			User::__DbgSetAllocFail(RHeap::EUser, (RHeap::TAllocFail)aArg1, aArg2);
       
  4169 			break;
       
  4170 		case EDiskFailure:
       
  4171 #if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4172 			iNotify->SetDiskMissing(aArg1);
       
  4173 			iNotify->SetWrongId(aArg2);
       
  4174 #endif
       
  4175 			break;
       
  4176 		}
       
  4177 	}
       
  4178 
       
  4179 
       
  4180 
       
  4181 
       
  4182 void CMsvServer::SetStartupState(TMsvServerChangeNotificationType aState)
       
  4183 	{
       
  4184 	iStartupState=aState;
       
  4185 	}
       
  4186 
       
  4187 const TDriveUnit &CMsvServer::Drive() const
       
  4188 	{
       
  4189 	return(iIndexDrive);
       
  4190 	}
       
  4191 
       
  4192 
       
  4193 
       
  4194 void CMsvServer::MailinitFinished(TInt aError, TDriveNumber aDriveNum)
       
  4195 	{
       
  4196 	// if mailinit exited sucessfully try and delete the
       
  4197 	// flag file.
       
  4198 	if(aError==KErrNone)
       
  4199 		{
       
  4200 		// remove the mailinit flag file, ignore errors it will just mean
       
  4201 		// we run mailinit next time the server starts and we require that
       
  4202 		// mailinit.exe handles this gracefully.
       
  4203 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4204 		if(iFs.SetSessionToPrivate(aDriveNum) == KErrNone)
       
  4205 #else
       
  4206 		// Just to ignore the warning.
       
  4207 		aDriveNum = aDriveNum;
       
  4208 		if(iFs.SetSessionToPrivate(iContext->Config().iDrive) == KErrNone)
       
  4209 #endif	  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4210 
       
  4211 			{
       
  4212 			iFs.Delete(KMsvStoreInitFileName);
       
  4213 			}
       
  4214 		}
       
  4215 #ifdef MSG_SERV_AUTO_CLOSE
       
  4216 	// we may have delayed shutdown to allow mailinit to finish, so
       
  4217 	// let the server shutdown if it wants to.
       
  4218 	CheckAndClose();
       
  4219 #endif
       
  4220 	}
       
  4221 
       
  4222 
       
  4223 TMsvServerStoreManager& CMsvServer::ServerStoreManager()
       
  4224 	{
       
  4225 	return iServerStoreManager;
       
  4226 	}
       
  4227 
       
  4228 void CMsvServer::GetNonOperationMtmDataL(TMsvId aServiceId, TNonOperationMtmDataType aMtmDataType, TPtrC8& aResultBuffer)
       
  4229 	{
       
  4230 	TBool active;
       
  4231 	TInt index = CheckMtmStatus(aServiceId, active);
       
  4232 
       
  4233 	if (index == KErrNotFound)
       
  4234 		{
       
  4235 		User::Leave(KErrNotFound);
       
  4236 		}
       
  4237 
       
  4238 	User::LeaveIfError(iMtmOperationQueueArray.At(index)->iMtm->GetNonOperationMtmData(aMtmDataType, aResultBuffer));
       
  4239 	}
       
  4240 
       
  4241 
       
  4242 /**
       
  4243 Checks client capabilty for readuserdata for performing search sort operation
       
  4244 */
       
  4245 void CMsvServer::PoliceSearchSortQueryReadRequestL(const RMessage2& aMsg, const char* aContextText)
       
  4246 	{
       
  4247 	// The client can read the entry under following circumstances.
       
  4248 	// 1. The client has Read User Data capability.
       
  4249 	// 2. The client does not have Read User Data but owns the entry.
       
  4250 
       
  4251 	// First check if the client is trusted with Read User Data.
       
  4252 	if( !aMsg.HasCapability(ECapabilityReadUserData) )
       
  4253 		{
       
  4254 		// Client not trusted with Read User data 
       
  4255 			{
       
  4256 			// Client missing capabilities - emit diagnostics and leave...
       
  4257 			User::LeaveIfError(PlatSec::CapabilityCheckFail(aMsg, ECapabilityReadUserData, aContextText));
       
  4258 			}
       
  4259 		}
       
  4260 	}
       
  4261 
       
  4262 
       
  4263 //**********************************
       
  4264 // CMsvTimer
       
  4265 //**********************************
       
  4266 
       
  4267 CMsvTimer::CMsvTimer(CMsvServer& aServer, TBool aCloseServer)
       
  4268 : CTimer(EPriorityLow), iServer(aServer), iCloseServer(aCloseServer)
       
  4269 	{}
       
  4270 
       
  4271 void CMsvTimer::RunL()
       
  4272 	{
       
  4273 	iServer.AttemptDelayedUpdating();
       
  4274 	if (iCloseServer)
       
  4275 		{
       
  4276 		CActiveScheduler::Stop();
       
  4277 		}
       
  4278 	}
       
  4279 
       
  4280 CMsvTimer* CMsvTimer::NewL(CMsvServer& aServer, TBool aCloseServer)
       
  4281 	{
       
  4282 	CMsvTimer* self = new(ELeave) CMsvTimer(aServer, aCloseServer);
       
  4283 	CleanupStack::PushL(self);
       
  4284 	self->ConstructL(); // CTimer
       
  4285 	CActiveScheduler::Add(self);
       
  4286 	CleanupStack::Pop();
       
  4287 	return self;
       
  4288 	}
       
  4289 
       
  4290 
       
  4291 //**********************************
       
  4292 // MessageServer
       
  4293 //**********************************
       
  4294 
       
  4295 EXPORT_C TVersion MessageServer::Version()
       
  4296 /** Returns the Message Server version number.
       
  4297 
       
  4298 @return Message server version number */
       
  4299 	{
       
  4300 	return TVersion(KMsvServerMajorVersionNumber,KMsvServerMinorVersionNumber,KMsvServerBuildVersionNumber);
       
  4301 	}
       
  4302 
       
  4303 
       
  4304 
       
  4305 
       
  4306 EXPORT_C TMsvId MessageServer::NullUidValue()
       
  4307 /** Returns the predefined message entry ID null value.
       
  4308 
       
  4309 @return Message entry ID null value */
       
  4310 	{
       
  4311 	return KMsvNullIndexEntryId;
       
  4312 	}
       
  4313 
       
  4314 
       
  4315 
       
  4316 
       
  4317 EXPORT_C TBool MessageServer::DriveContainsStore(RFs& aFs, TInt aDrive)
       
  4318 /** Checks if the specified drive has a Message Server index on it.
       
  4319 
       
  4320 @capability AllFiles If not within the message server process
       
  4321 @capability None If within the message server process
       
  4322 
       
  4323 @param aFs File server session
       
  4324 @param aDrive Drive to check, specified by a TDriveNumber value
       
  4325 @return True if aDrive has a Message Server index, otherwise false
       
  4326 @see TDriveNumber */
       
  4327 	{
       
  4328 	TParse parse1, parse2;
       
  4329 	TDriveUnit driveUnit(aDrive);
       
  4330 	TPtrC driveName(driveUnit.Name());
       
  4331 	
       
  4332 	// Check the existence of index file.
       
  4333 	parse1.Set(KMsvDefaultIndexFile,  &driveName, NULL);
       
  4334 	parse2.Set(KMsvDefaultIndexFile2, &driveName, NULL);
       
  4335 	TBool isMessageStoreExists =  BaflUtils::FileExists(aFs, parse1.FullName())
       
  4336 							  ||  BaflUtils::FileExists(aFs, parse2.FullName());
       
  4337 	
       
  4338 	// If index file is not present,
       
  4339 	// check the existence of index DB.
       
  4340 	if(!isMessageStoreExists)
       
  4341 		{
       
  4342 		parse1.Set(KMsvDbFile, &driveName, NULL);
       
  4343 		TFileName dBFile = parse1.FullName();   
       
  4344 		RSqlDatabase db;
       
  4345 		TRAPD(err, db.OpenL(dBFile));
       
  4346 		isMessageStoreExists = (KErrNone == err)? ETrue: EFalse;
       
  4347 		db.Close();
       
  4348 		}
       
  4349 	
       
  4350 	return isMessageStoreExists;
       
  4351 	}
       
  4352 	
       
  4353 	
       
  4354 
       
  4355 
       
  4356 EXPORT_C TInt MessageServer::CurrentDriveL(RFs& aFs)
       
  4357 /** Returns the drive that the Message Server is using to store messages.
       
  4358 
       
  4359 @capability AllFiles If not within the message server process
       
  4360 @capability None If within the message server process
       
  4361 @param aFs File server session
       
  4362 @return Drive used, specified by a TDriveNumber value
       
  4363 @see TDriveNumber */
       
  4364 	{
       
  4365 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4366 	aFs = aFs;		  // This avoids warning.
       
  4367 	
       
  4368 	// Get the current drive info from cenrep.
       
  4369 	CRepository* repository = CRepository::NewL(KUidConfigFile);
       
  4370 	TInt driveNum;
       
  4371 	TInt err = repository->Get(KCenRepCurrentDriveKey, driveNum);
       
  4372 	delete repository;
       
  4373 	
       
  4374 	if( (err != KErrNone) || (driveNum > EDriveZ) )
       
  4375 		{
       
  4376 		User::Leave(KErrNotFound);  
       
  4377 		}
       
  4378 	return driveNum;
       
  4379 
       
  4380 #else
       
  4381 	TMsvConfig config;
       
  4382 	CMsvServer::CurrentConfigL(aFs, config);
       
  4383 	return config.iDrive;
       
  4384 #endif	  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4385 	}
       
  4386 	
       
  4387 	
       
  4388 	
       
  4389 
       
  4390 /** Checks to see if the currently selected drive contains the correct mail store.
       
  4391 
       
  4392 If the message store is present on an external drive, we have to check if the same drive is
       
  4393 mounted or not before storing the mail.
       
  4394 
       
  4395 @return ETrue if the same drive is mounted. otherwise returns EFalse
       
  4396 @capability None
       
  4397 */
       
  4398 EXPORT_C TBool MessageServer::IsMessageStoreDrivePresentL(RFs& aFs)
       
  4399 	{   
       
  4400 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4401 	aFs = aFs;
       
  4402 	return ETrue;   
       
  4403 #else
       
  4404 	TUint uniqueId = 0;
       
  4405 	TMsvConfig config;
       
  4406 	CMsvServer::CurrentConfigL(aFs, config);
       
  4407 	//Check whether the drive and uid mentioned in the msgs.ini are mounted
       
  4408 	TVolumeInfo volumeInfo;
       
  4409 	uniqueId = config.iUniqueID;
       
  4410 
       
  4411 	User::LeaveIfError(aFs.Volume(volumeInfo, config.iDrive.operator TInt()));
       
  4412 	//Check whether the uid stored in msgs.ini and mounted drive's uid are same
       
  4413 	if(volumeInfo.iUniqueID == uniqueId)
       
  4414 		{
       
  4415 		return ETrue;
       
  4416 		}
       
  4417 	return EFalse;
       
  4418 #endif		  // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4419 	}
       
  4420 
       
  4421 
       
  4422 
       
  4423 
       
  4424 
       
  4425 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4426 /**
       
  4427  * IsMessageStoreSupported()
       
  4428  *
       
  4429  * @param TDriveNumber: The drive number of the drive.
       
  4430  * @return TBool: ETrue: If the drive has a valid version of message store.
       
  4431  *				EFalse: Otherwise.
       
  4432  */
       
  4433 EXPORT_C TBool MessageServer::IsMessageStoreSupported(TDriveNumber aDrive)
       
  4434 	{
       
  4435 	TParse parse;
       
  4436 	TPtrC driveName(TDriveUnit(aDrive).Name());
       
  4437 	
       
  4438 	// Check if the message index database 
       
  4439 	// exists and it has a valid version.
       
  4440 
       
  4441 	parse.Set(KMsvDbFile, &driveName, NULL);
       
  4442 	TFileName dBFile = parse.FullName();	
       
  4443 	RSqlDatabase db;
       
  4444 	TRAPD(err, db.OpenL(dBFile));
       
  4445 	if(KErrNone == err)
       
  4446 		{
       
  4447 		TInt version = 0;
       
  4448 		TSqlScalarFullSelectQuery query(db);
       
  4449 		_LIT8(KSelectVersionQuery, "SELECT version FROM VersionTable;");
       
  4450 		
       
  4451 		TRAP(err, version = query.SelectIntL(KSelectVersionQuery));	 
       
  4452 		if( (KErrNone == err) && (version == KCurrentDatabaseVersion) )
       
  4453 			{
       
  4454 			db.Close();
       
  4455 			return ETrue;
       
  4456 			}
       
  4457 		}
       
  4458 	// If the DB is already opened by message server, return ETrue.
       
  4459 	if(KErrInUse == err)
       
  4460 		{
       
  4461 		return ETrue;
       
  4462 		}
       
  4463 	db.Close();
       
  4464 	return EFalse;
       
  4465 	}
       
  4466 
       
  4467 #endif	  //#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4468