Index: src/ch/task.cpp
===================================================================
diff -u -rcac4819aa32d29c9feab400cadc083d713459a82 -r79b981925588ba300cae07d965e12aa590aa7a91
--- src/ch/task.cpp	(.../task.cpp)	(revision cac4819aa32d29c9feab400cadc083d713459a82)
+++ src/ch/task.cpp	(.../task.cpp)	(revision 79b981925588ba300cae07d965e12aa590aa7a91)
@@ -352,7 +352,8 @@
 
 TTaskProgressInfo::TTaskProgressInfo() :
 	m_stCurrentIndex(0),
-	m_ullCurrentFileProcessedSize(0)
+	m_ullCurrentFileProcessedSize(0),
+	m_stSubOperationIndex(0)
 {
 }
 
@@ -398,7 +399,94 @@
 	m_ullCurrentFileProcessedSize += ullSizeToAdd;
 }
 
+void TTaskProgressInfo::SetSubOperationIndex(size_t stSubOperationIndex)
+{
+	boost::unique_lock<boost::shared_mutex> lock(m_lock);
+	m_stSubOperationIndex = stSubOperationIndex;
+}
+
+size_t TTaskProgressInfo::GetSubOperationIndex() const
+{
+	boost::shared_lock<boost::shared_mutex> lock(m_lock);
+	return m_stSubOperationIndex;
+}
+
+void TTaskProgressInfo::IncreaseSubOperationIndex()
+{
+	boost::unique_lock<boost::shared_mutex> lock(m_lock);
+	++m_stSubOperationIndex;
+}
+
 ////////////////////////////////////////////////////////////////////////////
+// class TOperationDescription
+
+TOperationDescription::TOperationDescription() :
+	m_eOperation(eOperation_None)
+{
+}
+
+TOperationDescription::~TOperationDescription()
+{
+}
+
+void TOperationDescription::SetOperationType(EOperationType eOperation)
+{
+	switch(eOperation)
+	{
+	case eOperation_None:
+		THROW(_T("Cannot set operation type 'none'"), 0, 0, 0);
+		break;
+
+	case eOperation_Copy:
+		{
+			boost::unique_lock<boost::shared_mutex> lock(m_lock);
+			m_vSubOperations.clear();
+			m_vSubOperations.push_back(eSubOperation_Scanning);
+			m_vSubOperations.push_back(eSubOperation_Copying);
+			break;
+		}
+
+	case eOperation_Move:
+		{
+			boost::unique_lock<boost::shared_mutex> lock(m_lock);
+			m_vSubOperations.clear();
+			m_vSubOperations.push_back(eSubOperation_Scanning);
+			m_vSubOperations.push_back(eSubOperation_Copying);
+			m_vSubOperations.push_back(eSubOperation_Deleting);
+			break;
+		}
+
+	BOOST_STATIC_ASSERT(eOperation_Move == eOperation_Max - 1);
+
+	default:
+		THROW(_T("Unhandled case"), 0, 0, 0);
+	}
+
+	m_eOperation = eOperation;
+}
+
+EOperationType TOperationDescription::GetOperationType() const
+{
+	boost::shared_lock<boost::shared_mutex> lock(m_lock);
+	return m_eOperation;
+}
+
+size_t TOperationDescription::GetSubOperationsCount() const
+{
+	boost::shared_lock<boost::shared_mutex> lock(m_lock);
+	return m_vSubOperations.size();
+}
+
+ESubOperationType TOperationDescription::GetSubOperationAt(size_t stIndex) const
+{
+	boost::shared_lock<boost::shared_mutex> lock(m_lock);
+	if(stIndex >= m_vSubOperations.size())
+		THROW(_T("Index out of bounds"), 0, 0, 0);
+	else
+		return m_vSubOperations[stIndex];
+}
+
+////////////////////////////////////////////////////////////////////////////
 // CTask members
 CTask::CTask(chcore::IFeedbackHandler* piFeedbackHandler, size_t stSessionUniqueID) :
 	m_log(),
@@ -568,14 +656,12 @@
 
 void CTask::SetOperationType(EOperationType eOperationType)
 {
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	m_eOperation = eOperationType;
+	m_tOperation.SetOperationType(eOperationType);
 }
 
 EOperationType CTask::GetOperationType() const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	return m_eOperation;
+	return m_tOperation.GetOperationType();
 }
 
 // m_nBufferSize
@@ -654,6 +740,7 @@
 	if(bData)
 	{
 		m_clipboard.Load(ar, 0, bData);
+		ar >> m_tOperation;
 
 		m_files.Load(ar, 0, false);
 
@@ -690,15 +777,6 @@
 			THROW(_T("Wrong data read from stream"), 0, 0, 0);
 		}
 
-		ar >> iState;
-		if(iState >= eOperation_Copy && iState <= eOperation_Move)
-			m_eOperation = (EOperationType)iState;
-		else
-		{
-			BOOST_ASSERT(false);
-			THROW(_T("Wrong data read from stream"), 0, 0, 0);
-		}
-
 		ar >> m_bsSizes;
 		ar >> m_nPriority;
 
@@ -737,7 +815,10 @@
 	{
 		m_clipboard.Store(ar, 0, bData);
 
-		if(GetStatusNL(ST_STEP_MASK) > ST_SEARCHING)
+		ar << m_tOperation;
+
+		ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex());
+		if(eSubOperation != eSubOperation_Scanning)
 			m_files.Store(ar, 0, false);
 		else
 		{
@@ -753,7 +834,7 @@
 	{
 		ar << m_tTaskProgressInfo;
 
-		UINT uiStatus = (m_nStatus & ST_WRITE_MASK);
+		UINT uiStatus = m_nStatus;
 		ar << uiStatus;
 
 		// store current state (convert from waiting to processing state before storing)
@@ -763,17 +844,16 @@
 
 		ar << iState;
 
-		iState = m_eOperation;
-		ar << iState;
-
 		ar << m_bsSizes;
 		ar << m_nPriority;
 
 		time_t timeElapsed = m_localStats.GetTimeElapsed();
 		ar << timeElapsed;
 
 		m_clipboard.Store(ar, 0, bData);
-		if(GetStatusNL(ST_STEP_MASK) > ST_SEARCHING)
+
+		ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex());
+		if(eSubOperation != eSubOperation_Scanning)
 			m_files.Store(ar, 0, true);
 		else
 		{
@@ -968,17 +1048,19 @@
 	}
 
 	// second part
-	if( (m_nStatus & ST_STEP_MASK) == ST_DELETING )
+	EOperationType eOperationType = m_tOperation.GetOperationType();
+	ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex());
+	if(eSubOperation == eSubOperation_Deleting)
 		_tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+6));
-	else if( (m_nStatus & ST_STEP_MASK) == ST_SEARCHING )
+	else if(eSubOperation == eSubOperation_Scanning)
 		_tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+0));
-	else if(m_eOperation == eOperation_Copy)
+	else if(eOperationType == eOperation_Copy)
 	{
 		_tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+1));
 		if(!m_afFilters.IsEmpty())
 			_tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_FILTERING_STRING));
 	}
-	else if(m_eOperation == eOperation_Move)
+	else if(eOperationType == eOperation_Move)
 	{
 		_tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+2));
 		if(!m_afFilters.IsEmpty())
@@ -1190,9 +1272,6 @@
 	// log
 	m_log.logi(_T("Searching for files..."));
 
-	// update status
-	SetStatus(ST_SEARCHING, ST_STEP_MASK);
-
 	// delete the content of m_files
 	m_files.Clear();
 
@@ -1340,9 +1419,6 @@
 	// calc size of all files
 	CalculateTotalSize();
 
-	// change state to ST_COPYING - finished searching for files
-	SetStatus(ST_COPYING, ST_STEP_MASK);
-
 	// save task status
 	Store(true);
 	Store(false);
@@ -2235,7 +2311,7 @@
 			return eSubResult_KillRequest;
 		}
 
-		// update m_stCurrentIndex, getting current CFileInfo
+		// update m_stNextIndex, getting current CFileInfo
 		CFileInfoPtr spFileInfo = m_files.GetAt(m_tTaskProgressInfo.GetCurrentIndex());
 
 		// set dest path with filename
@@ -2357,20 +2433,9 @@
 	// delete buffer - it's not needed
 	ccp.dbBuffer.Delete();
 
-	// change status
-	if(GetOperationType() == eOperation_Move)
-	{
-		SetStatus(ST_DELETING, ST_STEP_MASK);
-		// set the index to 0 before deleting
-		m_tTaskProgressInfo.SetCurrentIndex(0);
-	}
-	else
-	{
-		SetTaskState(eTaskState_Finished);
+	// to look better (as 100%) - increase current index by 1
+	m_tTaskProgressInfo.SetCurrentIndex(stSize);
 
-		// to look better - increase current index by 1
-		m_tTaskProgressInfo.SetCurrentIndex(stSize);
-	}
 	// log
 	m_log.logi(_T("Finished processing in ProcessFiles"));
 
@@ -2493,52 +2558,60 @@
 		// determine when to scan directories
 		bool bReadTasksSize = GetConfig().get_bool(PP_CMREADSIZEBEFOREBLOCKING);
 
-		// check if we're allowed to continue searching for files
-		if(!bReadTasksSize)
+		// wait for permission to really start (but only if search for files is not allowed to start regardless of the lock)
+		size_t stSubOperationIndex = m_tTaskProgressInfo.GetSubOperationIndex();
+		if(!bReadTasksSize || stSubOperationIndex != 0 || m_tOperation.GetSubOperationsCount() == 0 || m_tOperation.GetSubOperationAt(0) != eSubOperation_Scanning)
 			eResult = CheckForWaitState();	// operation limiting
 
-		// start tracking time
-		if(eResult == eSubResult_Continue)
+		// start tracking time for this thread
+		m_localStats.EnableTimeTracking();
+
+		for(; stSubOperationIndex < m_tOperation.GetSubOperationsCount() && eResult == eSubResult_Continue; ++stSubOperationIndex)
 		{
-			m_localStats.EnableTimeTracking();
+			// set current sub-operation index to allow resuming
+			m_tTaskProgressInfo.SetSubOperationIndex(stSubOperationIndex);
 
-			// search for files if needed
-			if((GetStatus(ST_STEP_MASK) == ST_NULL_STATUS || GetStatus(ST_STEP_MASK) == ST_SEARCHING))
+			ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(stSubOperationIndex);
+			switch(eSubOperation)
 			{
+			case eSubOperation_Scanning:
 				// get rid of info about processed sizes
 				m_localStats.SetProcessedSize(0);
 				m_localStats.SetTotalSize(0);
 
 				// start searching
 				eResult = RecurseDirectories();
-			}
-		}
 
-		// check for free space
-		if(eResult == eSubResult_Continue)
-			eResult = CheckForFreeSpaceFB();
+				// check for free space
+				if(eResult == eSubResult_Continue)
+					eResult = CheckForFreeSpaceFB();
 
-		if(eResult == eSubResult_Continue && bReadTasksSize)
-		{
-			m_localStats.DisableTimeTracking();
+				// if we didn't wait for permission to start earlier, then ask now (but only in case this is the first search)
+				if(eResult == eSubResult_Continue && bReadTasksSize && stSubOperationIndex == 0)
+				{
+					m_localStats.DisableTimeTracking();
 
-			eResult = CheckForWaitState();
+					eResult = CheckForWaitState();
 
-			m_localStats.EnableTimeTracking();
-		}
+					m_localStats.EnableTimeTracking();
+				}
 
-		// Phase II - copying/moving
-		if(eResult == eSubResult_Continue && GetStatus(ST_STEP_MASK) == ST_COPYING)
-		{
-			// decrease processed in ctaskarray - the rest will be done in ProcessFiles
-			//m_rtGlobalStats.DecreaseGlobalProcessedSize(GetProcessedSize());
-			eResult = ProcessFiles();
-		}
+				break;
 
-		// deleting data - III phase
-		if(eResult == eSubResult_Continue && GetStatus(ST_STEP_MASK) == ST_DELETING)
-			eResult = DeleteFiles();
+			case eSubOperation_Copying:
+				eResult = ProcessFiles();
+				break;
 
+			case eSubOperation_Deleting:
+				eResult = DeleteFiles();
+				break;
+
+			default:
+				BOOST_ASSERT(false);
+				THROW(_T("Unhandled case"), 0, 0, 0);
+			}
+		}
+
 		// refresh time
 		m_localStats.DisableTimeTracking();
 
@@ -2576,10 +2649,9 @@
 		}
 
 		// perform cleanup dependent on currently executing subtask
-		switch(GetStatus(ST_STEP_MASK))
+		switch(m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex()))
 		{
-		case ST_NULL_STATUS:
-		case ST_SEARCHING:
+		case eSubOperation_Scanning:
 			m_files.Clear();		// get rid of m_files contents
 			Store(true);			// save state of a task
 			break;
Index: src/ch/task.h
===================================================================
diff -u -rcac4819aa32d29c9feab400cadc083d713459a82 -r79b981925588ba300cae07d965e12aa590aa7a91
--- src/ch/task.h	(.../task.h)	(revision cac4819aa32d29c9feab400cadc083d713459a82)
+++ src/ch/task.h	(.../task.h)	(revision 79b981925588ba300cae07d965e12aa590aa7a91)
@@ -30,15 +30,7 @@
 
 #define ST_NULL_STATUS		0x00000000
 
-#define ST_WRITE_MASK		0x000fffff
-
 //------------------------------------
-#define ST_STEP_MASK		0x000000ff
-#define ST_SEARCHING		0x00000001
-#define ST_COPYING			0x00000002
-#define ST_DELETING			0x00000003
-
-//------------------------------------
 #define ST_SPECIAL_MASK		0x0000f000
 // simultaneous flags
 #define ST_IGNORE_DIRS		0x00001000
@@ -63,10 +55,25 @@
 // enum represents type of the operation handled by the task
 enum EOperationType
 {
+	eOperation_None,
 	eOperation_Copy,
-	eOperation_Move
+	eOperation_Move,
+
+	// add new operation types before this enum value
+	eOperation_Max
 };
 
+enum ESubOperationType
+{
+	eSubOperation_None,
+	eSubOperation_Scanning,
+	eSubOperation_Copying,
+	eSubOperation_Deleting,
+
+	// add new operation types before this one
+	eSubOperation_Max
+};
+
 // special value representing no task
 #define NO_TASK_SESSION_UNIQUE_ID				0
 
@@ -323,6 +330,10 @@
 	unsigned long long GetCurrentFileProcessedSize() const;
 	void IncreaseCurrentFileProcessedSize(unsigned long long ullSizeToAdd);
 
+	void SetSubOperationIndex(size_t stSubOperationIndex);
+	size_t GetSubOperationIndex() const;
+	void IncreaseSubOperationIndex();
+
 	template<class Archive>
 	void load(Archive& ar, unsigned int /*uiVersion*/)
 	{
@@ -332,10 +343,14 @@
 		unsigned long long ullCurrentFileProcessedSize = 0;
 		ar >> ullCurrentFileProcessedSize;
 
+		size_t stSubOperationIndex = 0;
+		ar >> stSubOperationIndex;
+
 		boost::unique_lock<boost::shared_mutex> lock(m_lock);
 
 		m_stCurrentIndex = stCurrentIndex;
 		m_ullCurrentFileProcessedSize = ullCurrentFileProcessedSize;
+		m_stSubOperationIndex = stSubOperationIndex;
 	}
 
 	template<class Archive>
@@ -345,24 +360,67 @@
 
 		size_t stCurrentIndex = m_stCurrentIndex;
 		unsigned long long ullCurrentFileProcessedSize = m_ullCurrentFileProcessedSize;
+		size_t stSubOperationIndex = m_stSubOperationIndex;
 		
 		m_lock.unlock_shared();
 
 		ar << stCurrentIndex;
 		ar << ullCurrentFileProcessedSize;
+		ar << stSubOperationIndex;
 	}
 
 	BOOST_SERIALIZATION_SPLIT_MEMBER();
 
 private:
+	volatile size_t m_stSubOperationIndex;		 // index of sub-operation from TOperationDescription
 	volatile size_t m_stCurrentIndex;   // index to the m_files array stating currently processed item
 	volatile unsigned long long m_ullCurrentFileProcessedSize;	// count of bytes processed for current file
 
 	mutable boost::shared_mutex m_lock;
 };
 
 ///////////////////////////////////////////////////////////////////////////
+// TOperationDescription
+
+// class describes the sub-operations to be performed
+class TOperationDescription
+{
+public:
+	TOperationDescription();
+	~TOperationDescription();
+
+	void SetOperationType(EOperationType eOperation);
+	EOperationType GetOperationType() const;
+
+	size_t GetSubOperationsCount() const;
+	ESubOperationType GetSubOperationAt(size_t stIndex) const;
+
+	template<class Archive>
+	void load(Archive& ar, unsigned int /*uiVersion*/)
+	{
+		EOperationType eOperation = eOperation_None;
+		ar >> eOperation;
+		SetOperationType(eOperation);
+	}
+
+	template<class Archive>
+	void save(Archive& ar, unsigned int /*uiVersion*/) const
+	{
+		ar << m_eOperation;
+	}
+
+	BOOST_SERIALIZATION_SPLIT_MEMBER();
+
+private:
+	EOperationType m_eOperation;
+	std::vector<ESubOperationType> m_vSubOperations;
+
+	mutable boost::shared_mutex m_lock;
+};
+
+///////////////////////////////////////////////////////////////////////////
 // CTask
+
 class CTask
 {
 protected:
@@ -526,8 +584,6 @@
 	CClipboardArray m_clipboard;        // original paths with which we started operation
 	CDestPath m_dpDestPath;             // destination path
 
-	EOperationType m_eOperation;					// operation which is to be performed by this task object
-
 	// task settings
 	int m_nPriority;                    // task priority (really processing thread priority)
 
@@ -543,6 +599,8 @@
 	// changing fast
 	volatile ETaskCurrentState m_eCurrentState;     // current state of processing this task represents
 
+	TOperationDescription m_tOperation;		// manages the operation and its suboperations
+
 	volatile UINT m_nStatus;            // what phase of the operation is this task in
 
 	TTaskProgressInfo m_tTaskProgressInfo;	// task progress information