// 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);
		// RDebug::Print(_L("TFsNotificationRequest::DoRequestL Not-OutOver- iClientHead==%d, iClientTail==%d"),notifyRequest->iClientHead,notifyRequest->iClientTail);
		}
	else
		{
		notifyRequest->SetActive(CFsNotifyRequest::EInactive);
		
		// RDebug::Print(_L("TFsNotificationRequest::DoRequestL OutOver- iClientHead==%d, iClientTail==%d"),notifyRequest->iClientHead,notifyRequest->iClientTail);
		
		// If the user is in OutstandingOverflow notification state, 
		// then we can set iClientHead to be equal to iServerTail now.
		// That way if the client requests again and the state will go 
		// back to active, the server will see that buffer as empty 
		// rather than full/overflow.
		
		notifyRequest->iClientHead = notifyRequest->iClientTail;
		}
	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->Message(),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 = CFsNotificationInfo::DriveNumber(path);
	if(path.Length() >= 2)
	    {
	    if(path[1] != (TText)':')
	        {
	        if(path[0]!=(TText)'*')
	            {
	            return KErrPathNotFound;
	            }
	        }
	    else // 2nd char is ':' 
	        {
	        if(driveNum < EDriveA  || driveNum > EDriveZ)
	            {
	            if(path[0]!=(TText)'?')
	                return KErrPathNotFound;
	            }
	        }
	    }

	CleanupStack::PushL(notifyRequest);
	TPtrC pathPtr(path);
	if(driveNum!=KErrNotFound || ((path.Length() >=1) && path[0]=='?'))
	    //Remove the drive: part of the the path if it's got one.
	    pathPtr.Set(path.Mid(2));
	CFsNotificationPathFilter* filter = CFsNotificationPathFilter::NewL(pathPtr,filename,driveNum);

	//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

