// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32\sfile\sf_notifier_handlers.cpp
// 
//
#include "sf_std.h"
#include "sf_notifier.h"

#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION

TInt TFsNotificationOpen::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNone;
	}

TInt TFsNotificationOpen::DoRequestL(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationOpen::DoRequestL()"));
	//Check whether we've got a notification manager 
	//If not, create it and call OpenL
	if(!FsNotificationManager::IsInitialised())
		{
		FsNotificationManager::OpenL();
		}
	
	//Create a new CFsNotifyRequest and add it to the manager
	CFsNotifyRequest* notifyRequest = CFsNotifyRequest::NewL();

	//Get handle and add request to manager and Session->Handles
	TInt handle = 0;
	TBool addedToManager = EFalse;
	TRAPD(ret,HandleRequestL(aRequest, notifyRequest, handle,addedToManager));	
	if (ret!=KErrNone)
		{
		//Remove request from Session->Handles if it was already added
		if (handle!=0)
			aRequest->Session()->Handles().Remove(handle,ETrue);
		
		//Remove request from manager
		if(addedToManager)
			{
			FsNotificationManager::Lock();
			FsNotificationManager::RemoveNotificationRequest(notifyRequest);
			FsNotificationManager::Unlock();
			}
		delete notifyRequest;
		return(ret);
		}
	
	notifyRequest->iSession = aRequest->Session();
	aRequest->Session()->IncResourceCount();
	return ret;
	}

//Get handle and add request to Session->Handles
void TFsNotificationOpen::HandleRequestL(CFsRequest* aRequest, CFsNotifyRequest* aNotifyRequest, TInt& aHandle,TBool& aAddedToManager)
	{
	aAddedToManager = EFalse;
	FsNotificationManager::AddNotificationRequestL(aNotifyRequest);
	aAddedToManager = ETrue;
	aHandle = aRequest->Session()->Handles().AddL(aNotifyRequest,ETrue);
	TPtrC8 pH((TUint8*)&aHandle, sizeof(TInt));
	aRequest->WriteL(KMsgPtr3,pH);
	}

TInt TFsNotificationBuffer::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNone;
	}

TInt TFsNotificationBuffer::DoRequestL(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationBuffer::DoRequestL()"));
	HBufC8* buffer = (HBufC8*)(aRequest->Message().Ptr0());
	TInt handle = aRequest->Message().Int3();
	CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*)SessionObjectFromHandle(handle,0,aRequest->Session());
	if(!notifyRequest)
		return KErrBadHandle;
	if(!buffer)
		return KErrArgument;

	notifyRequest->iClientBufferSize = aRequest->Message().Int1();
	notifyRequest->iBufferMsg = aRequest->Message();
	return KErrNone;
	}

TInt TFsNotificationRequest::Initialise(CFsRequest* aRequest)
	{
	TInt handle = aRequest->Message().Int3();	
	CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*)SessionObjectFromHandle(handle,0,aRequest->Session());
	if(!notifyRequest)
		return KErrBadHandle;
	
	//Check the tail's validity
	TInt tail;
	TPckg<TInt> tailPkg(tail);
	TInt r = aRequest->Read(KMsgPtr0,tailPkg);
	
	if(r!=KErrNone || tail < 0 || tail > notifyRequest->iClientBufferSize)
		return KErrArgument;
		
	return KErrNone;
	}

TInt TFsNotificationRequest::DoRequestL(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationRequest::DoRequestL()"));
	//We need to check whether there is anything in the buffer
	//If so we should complete straight away.
	FsNotificationManager::Lock();
	
	//Get notification request
	TInt handle = aRequest->Message().Int3();	
	CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*)SessionObjectFromHandle(handle,0,aRequest->Session());
	if(!notifyRequest)
		{
		FsNotificationManager::Unlock();
		return KErrBadHandle;
		}
	
	TInt r = notifyRequest->SetClientMessage(aRequest->Message());
	if(r != KErrNone)
		{
		FsNotificationManager::Unlock();
		return r;
		}

	CFsNotifyRequest::TNotifyRequestStatus status = notifyRequest->ActiveStatus();
	if(status==CFsNotifyRequest::EOutstanding ||
		status==CFsNotifyRequest::EOutstandingOverflow)
		{
		notifyRequest->CompleteClientRequest(KErrNone);
		}

	//Update Status
	if(status!=CFsNotifyRequest::EOutstandingOverflow)
		{
		notifyRequest->SetActive(CFsNotifyRequest::EActive);
		
		// DEF140387:
		// If this is not the first call to RequestNotifications then if the 
		// user just got an overflow notification (and requested again) 
		// then its possible that iClientTail is not zero now.
	
		// We should set iClientHead to iClientTail, otherwise the client
		// can receive another overflow straight away.
		notifyRequest->iClientHead = notifyRequest->iClientTail;
		}
	else
		{
		notifyRequest->SetActive(CFsNotifyRequest::EInactive);
		}
	FsNotificationManager::Unlock();
	return r;
	}

TInt TFsNotificationCancel::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNone;
	}

TInt TFsNotificationCancel::DoRequestL(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationCancel::DoRequestL()"));
	FsNotificationManager::Lock();
	
	//Get notification request and deactivate filter
	TInt handle = aRequest->Message().Int3();	
	CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*)SessionObjectFromHandle(handle,0,aRequest->Session());
	if(!notifyRequest)
		{
		FsNotificationManager::Unlock();
		return KErrBadHandle;
		}
	
	if(notifyRequest->ClientMsgHandle()!=0)
		{	
		notifyRequest->SetActive(CFsNotifyRequest::EInactive);
		notifyRequest->CompleteClientRequest(KErrCancel,ETrue);
		}
	FsNotificationManager::Unlock();
	return KErrNone;
	}

TInt TFsNotificationSubClose::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNone;
	}

TInt TFsNotificationSubClose::DoRequestL(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationSubClose::DoRequestL()"));
	FsNotificationManager::Lock();
	
	//We need to complete the buffer request here as this type of request is not
	//completed in the normal way as it is kept open in order that we can access the buffer
	//in the client-side for the lifetime of this subsession.
	TInt handle = aRequest->Message().Int3();
	CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*) SessionObjectFromHandle(handle,0,aRequest->Session());
	if(!notifyRequest)
		{
		FsNotificationManager::Unlock();
		return KErrBadHandle;
		}
	
	notifyRequest->RemoveFilters();
	notifyRequest->CloseNotification(); //Completes the buffer and the client requests.
	
	TInt count = FsNotificationManager::Count();
	
	//Also deletes notifyRequest
	aRequest->Session()->Handles().Remove(handle,ETrue);
	if(count==1)
		{
		//If this is the last request then we need to remove the manager
		FsNotificationManager::Close();
		}
	
	FsNotificationManager::Unlock();
	aRequest->Session()->DecResourceCount();
	notifyRequest = NULL;

	return(KErrNone);
	}

TInt TFsNotificationAdd::Initialise(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationAdd::Initialise()"));
	TUint filter = (TUint) aRequest->Message().Int0();
	//If it's AllOps then it's ok
	if (filter!=TFsNotification::EAllOps)
		{

		TInt invalid = filter & ~KNotificationValidFiltersMask;
		//Check: Non-valid values ARE NOT set
		//		 and valid values ARE set.
		if(invalid || !filter)
			{
			return KErrArgument;
			}
		}
	
	TFileName path;
	TInt r = aRequest->Read(KMsgPtr1,path);
	if(r != KErrNone)
		{
		return r;
		}
	
	if(path.Length() >= 2)
		r=PathCheck(aRequest,path.Mid(2),&KCapFsSysFileTemp,&KCapFsPriFileTemp,&KCapFsROFileTemp, __PLATSEC_DIAGNOSTIC_STRING("Notification Add Filter"));
	return r;
	}

TInt TFsNotificationAdd::DoRequestL(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationAdd::DoRequestL()"));
	TInt handle = aRequest->Message().Int3();
	CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*) SessionObjectFromHandle(handle,0,aRequest->Session());
	if(!notifyRequest)
		return KErrBadHandle;
	
	TFileName path;
	aRequest->Read(KMsgPtr1,path);
	
	TFileName filename;
	TInt r = aRequest->Read(KMsgPtr2,filename);
	if(r!= KErrNone)
		return r;
	
	__PRINT2(_L("TFsNotificationAdd::AddNotification() path=%S, filename=%S"),&path,&filename);
	
	//If this is a path starting with 'drive-letter:'
	TInt driveNum = FsNotificationHelper::DriveNumber(path);
	if(path.Length() >= 2 && (driveNum < 0 || driveNum > 25) && ((TChar)driveNum)!=((TChar)'?') && ((TChar)path[1])==(TChar)':')
		{
		return KErrPathNotFound;
		}

	CleanupStack::PushL(notifyRequest);
	CFsNotificationPathFilter* filter = CFsNotificationPathFilter::NewL(path,filename);

	//Bitmask of filter types
	TUint filterMask = (TUint) aRequest->Message().Int0();
	
	r = notifyRequest->AddFilterL(filter,filterMask);
	CleanupStack::Pop(notifyRequest);

	if(r == KErrNone)
		{
		FsNotificationManager::Lock();
		//Increment global filter register
		FsNotificationManager::SetFilterRegisterMask(filterMask,(TBool)ETrue);
		FsNotificationManager::Unlock();
		}
	return r;
	}

TInt TFsNotificationRemove::Initialise(CFsRequest* /*aRequest*/)
	{
	__PRINT(_L("TFsNotificationRemove::Initialise()"));
	return KErrNone;
	}

TInt TFsNotificationRemove::DoRequestL(CFsRequest* aRequest)
	{
	__PRINT(_L("TFsNotificationRemove::DoRequestL()"));
	FsNotificationManager::Lock();
	
	TInt handle = aRequest->Message().Int3();
	CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*) SessionObjectFromHandle(handle,0,aRequest->Session());
	if(!notifyRequest)
		{
		FsNotificationManager::Unlock();
		return KErrBadHandle;
		}
	
	TInt r = notifyRequest->RemoveFilters();
	FsNotificationManager::Unlock();
	return r;
	}

#else //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION

CFsObjectCon* FsNotificationManager::iNotifyRequests = NULL;

CFsNotifyRequest::CFsNotifyRequest()
	{
	}

CFsNotifyRequest::~CFsNotifyRequest()
	{
	}

TInt TFsNotificationOpen::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationOpen::DoRequestL(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

void TFsNotificationOpen::HandleRequestL(CFsRequest* /*aRequest*/, CFsNotifyRequest* /*aNotifyRequest*/, TInt& /*aHandle*/,TBool& /*aAddedToManager*/)
	{
	User::Leave(KErrNotSupported);
	}

TInt TFsNotificationBuffer::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationBuffer::DoRequestL(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationRequest::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationRequest::DoRequestL(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationCancel::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationCancel::DoRequestL(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationSubClose::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationSubClose::DoRequestL(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationAdd::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationAdd::DoRequestL(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationRemove::Initialise(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

TInt TFsNotificationRemove::DoRequestL(CFsRequest* /*aRequest*/)
	{
	return KErrNotSupported;
	}

#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION

