Index: src/ch/FeedbackFileErrorDlg.cpp
===================================================================
diff -u -r3921d82d9605d98b2281f3f42d9f9c8385b89a3e -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackFileErrorDlg.cpp	(.../FeedbackFileErrorDlg.cpp)	(revision 3921d82d9605d98b2281f3f42d9f9c8385b89a3e)
+++ src/ch/FeedbackFileErrorDlg.cpp	(.../FeedbackFileErrorDlg.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -25,6 +25,16 @@
 {
 }
 
+bool CFeedbackFileErrorDlg::IsApplyToAllItemsChecked() const
+{
+	return m_bAllItems;
+}
+
+const chengine::FeedbackErrorRuleList& CFeedbackFileErrorDlg::GetRules() const
+{
+	return m_feedbackRules;
+}
+
 void CFeedbackFileErrorDlg::DoDataExchange(CDataExchange* pDX)
 {
 	ictranslate::CLanguageDialog::DoDataExchange(pDX);
Index: src/ch/FeedbackFileErrorDlg.h
===================================================================
diff -u -r12ee49f6bf1f8921500ee2078e0a8c2d7b6d2a45 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackFileErrorDlg.h	(.../FeedbackFileErrorDlg.h)	(revision 12ee49f6bf1f8921500ee2078e0a8c2d7b6d2a45)
+++ src/ch/FeedbackFileErrorDlg.h	(.../FeedbackFileErrorDlg.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -19,6 +19,8 @@
 #ifndef __FEEDBACKFILEERRORDLG_H__
 #define __FEEDBACKFILEERRORDLG_H__
 
+#include "../libchengine/FeedbackErrorRuleList.h"
+
 // CFeedbackFileErrorDlg dialog
 class CFeedbackFileErrorDlg : public ictranslate::CLanguageDialog
 {
@@ -28,23 +30,30 @@
 	CFeedbackFileErrorDlg(const wchar_t* pszSrcPath, const wchar_t* pszDstPath, unsigned long ulSysError, CWnd* pParent = nullptr);   // standard constructor
 	virtual ~CFeedbackFileErrorDlg();
 
-	afx_msg void OnBnClickedRetryButton();
-	afx_msg void OnBnClickedSkipButton();
-	afx_msg void OnBnClickedPauseButton();
-	afx_msg void OnBnClickedCancel();
+	bool IsApplyToAllItemsChecked() const;
 
+	const chengine::FeedbackErrorRuleList& GetRules() const;
+
 protected:
 	void DoDataExchange(CDataExchange* pDX) override;    // DDX/DDV support
 	void OnCancel() override;
+	BOOL OnInitDialog() override;
 
+	afx_msg void OnBnClickedRetryButton();
+	afx_msg void OnBnClickedSkipButton();
+	afx_msg void OnBnClickedPauseButton();
+	afx_msg void OnBnClickedCancel();
+
 	DECLARE_MESSAGE_MAP()
-public:
-	BOOL m_bAllItems;
+
+private:
+	BOOL m_bAllItems = FALSE;
 	CStatic m_ctlErrorInfo;
 	CString m_strSrcPath;
 	CString m_strDstPath;
-	unsigned long m_ulSysError;
-	BOOL OnInitDialog() override;
+	unsigned long m_ulSysError = 0;
+
+	chengine::FeedbackErrorRuleList m_feedbackRules;	// feedback rules resulting from choices made in this dialog box
 };
 
 #endif
Index: src/ch/FeedbackHandler.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackHandler.cpp	(.../FeedbackHandler.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/ch/FeedbackHandler.cpp	(.../FeedbackHandler.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -30,78 +30,63 @@
 using namespace chengine;
 using namespace string;
 
-CFeedbackHandler::CFeedbackHandler() :
-	TFeedbackHandlerBase()
+chengine::EFeedbackResult CFeedbackHandler::FileError(const TString& strSrcPath, const TString& strDstPath, EFileError /*eFileError*/, unsigned long ulError, FeedbackErrorRuleList& rNewRules)
 {
-}
-
-CFeedbackHandler::~CFeedbackHandler()
-{
-}
-
-TFeedbackResult CFeedbackHandler::FileError(const TString& strSrcPath, const TString& strDstPath, EFileError /*eFileError*/, unsigned long ulError)
-{
-	EFeedbackResult eResult = eResult_Unknown;
-	if(HasFileErrorPermanentResponse(eResult))
-		return TFeedbackResult(eResult, true);
-
 	CFeedbackFileErrorDlg dlg(strSrcPath.c_str(), strDstPath.c_str(), ulError);
-	eResult = (EFeedbackResult)dlg.DoModal();
+	EFeedbackResult eResult = (EFeedbackResult)dlg.DoModal();
 
-	if (dlg.m_bAllItems)
-		SetFileErrorPermanentResponse(eResult);
+	if(!dlg.GetRules().IsEmpty())
+		rNewRules = dlg.GetRules();
 
-	return TFeedbackResult(eResult, false);
+	return eResult;
 }
 
-TFeedbackResult CFeedbackHandler::FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo)
+chengine::EFeedbackResult CFeedbackHandler::FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo, FeedbackAlreadyExistsRuleList& rNewRules)
 {
-	EFeedbackResult eResult = eResult_Unknown;
-	if(HasFileAlreadyExistsPermanentResponse(eResult))
-		return TFeedbackResult(eResult, true);
-
 	CFeedbackReplaceDlg dlg(spSrcFileInfo, spDstFileInfo);
-	eResult = (EFeedbackResult)dlg.DoModal();
+	EFeedbackResult eResult = (EFeedbackResult)dlg.DoModal();
 
-	if(dlg.IsApplyToAllItemsChecked())
-		SetFileAlreadyExistsPermanentResponse(eResult);
+	if(!dlg.GetRules().IsEmpty())
+		rNewRules = dlg.GetRules();
 
-	return TFeedbackResult(eResult, false);
+	return eResult;
 }
 
-TFeedbackResult CFeedbackHandler::NotEnoughSpace(const TString& strSrcPath, const TString& strDstPath, unsigned long long ullRequiredSize)
+chengine::EFeedbackResult CFeedbackHandler::NotEnoughSpace(const TString& strSrcPath, const TString& strDstPath, unsigned long long ullRequiredSize, FeedbackNotEnoughSpaceRuleList& rNewRules)
 {
-	EFeedbackResult eResult = eResult_Unknown;
-	if(HasNotEnoughSpacePermanentResponse(eResult))
-		return TFeedbackResult(eResult, true);
-
 	CFeedbackNotEnoughSpaceDlg dlg(ullRequiredSize, strSrcPath.c_str(), strDstPath.c_str());
-	eResult = (EFeedbackResult) dlg.DoModal();
+	EFeedbackResult eResult = (EFeedbackResult) dlg.DoModal();
 
-	if (dlg.m_bAllItems)
-		SetNotEnoughSpacePermanentResponse(eResult);
+	if(!dlg.GetRules().IsEmpty())
+		rNewRules = dlg.GetRules();
 
-	return TFeedbackResult(eResult, false);
+	return eResult;
 }
 
-TFeedbackResult CFeedbackHandler::OperationFinished()
+chengine::EFeedbackResult CFeedbackHandler::OperationEvent(EOperationEvent eEvent, FeedbackOperationEventRuleList&)
 {
-	if (GetPropValue<PP_SNDPLAYSOUNDS>(GetConfig()))
+	switch(eEvent)
 	{
-		CString strPath = GetPropValue<PP_SNDFINISHEDSOUNDPATH>(GetConfig());
-		PlaySound(GetApp().ExpandPath(strPath), nullptr, SND_FILENAME | SND_ASYNC);
+	case eOperationEvent_Finished:
+	{
+		if(GetPropValue<PP_SNDPLAYSOUNDS>(GetConfig()))
+		{
+			CString strPath = GetPropValue<PP_SNDFINISHEDSOUNDPATH>(GetConfig());
+			PlaySound(GetApp().ExpandPath(strPath), nullptr, SND_FILENAME | SND_ASYNC);
+		}
+		break;
 	}
-
-	return TFeedbackResult(eResult_Unknown, true);
-}
-
-TFeedbackResult CFeedbackHandler::OperationError()
-{
-	if (GetPropValue<PP_SNDPLAYSOUNDS>(GetConfig()))
+	case eOperationEvent_Error:
 	{
-		CString strPath = GetPropValue<PP_SNDERRORSOUNDPATH>(GetConfig());
-		PlaySound(GetApp().ExpandPath(strPath), nullptr, SND_FILENAME | SND_ASYNC);
+		if(GetPropValue<PP_SNDPLAYSOUNDS>(GetConfig()))
+		{
+			CString strPath = GetPropValue<PP_SNDERRORSOUNDPATH>(GetConfig());
+			PlaySound(GetApp().ExpandPath(strPath), nullptr, SND_FILENAME | SND_ASYNC);
+		}
+
+		break;
 	}
+	}
 
-	return TFeedbackResult(eResult_Unknown, true);
+	return eResult_Unknown;
 }
Index: src/ch/FeedbackHandler.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackHandler.h	(.../FeedbackHandler.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/ch/FeedbackHandler.h	(.../FeedbackHandler.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -19,25 +19,21 @@
 #ifndef __FEEDBACKHANDLER_H__
 #define __FEEDBACKHANDLER_H__
 
-#include "../libchengine/TFeedbackHandlerBase.h"
+#include "../libchengine/IFeedbackHandler.h"
 
 namespace string
 {
 	class TString;
 }
 
-class CFeedbackHandler : public chengine::TFeedbackHandlerBase
+class CFeedbackHandler : public chengine::IFeedbackHandler
 {
 public:
-	CFeedbackHandler();
-	virtual ~CFeedbackHandler();
+	chengine::EFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, chengine::EFileError eFileError, unsigned long ulError, chengine::FeedbackErrorRuleList& rNewRules) override;
+	chengine::EFeedbackResult FileAlreadyExists(const chengine::TFileInfo& spSrcFileInfo, const chengine::TFileInfo& spDstFileInfo, chengine::FeedbackAlreadyExistsRuleList& rNewRules) override;
+	chengine::EFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize, chengine::FeedbackNotEnoughSpaceRuleList& rNewRules) override;
+	chengine::EFeedbackResult OperationEvent(chengine::EOperationEvent eEvent, chengine::FeedbackOperationEventRuleList& rNewRules) override;
 
-	chengine::TFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, chengine::EFileError eFileError, unsigned long ulError) override;
-	chengine::TFeedbackResult FileAlreadyExists(const chengine::TFileInfo& spSrcFileInfo, const chengine::TFileInfo& spDstFileInfo) override;
-	chengine::TFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize) override;
-	chengine::TFeedbackResult OperationFinished() override;
-	chengine::TFeedbackResult OperationError() override;
-
 protected:
 	friend class CFeedbackHandlerFactory;
 };
Index: src/ch/FeedbackNotEnoughSpaceDlg.cpp
===================================================================
diff -u -r3921d82d9605d98b2281f3f42d9f9c8385b89a3e -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackNotEnoughSpaceDlg.cpp	(.../FeedbackNotEnoughSpaceDlg.cpp)	(revision 3921d82d9605d98b2281f3f42d9f9c8385b89a3e)
+++ src/ch/FeedbackNotEnoughSpaceDlg.cpp	(.../FeedbackNotEnoughSpaceDlg.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -42,7 +42,16 @@
 	m_vstrFiles.push_back(pszSrcPath);
 }
 
+bool CFeedbackNotEnoughSpaceDlg::IsApplyToAllItemsChecked() const
+{
+	return m_bAllItems;
+}
 
+const chengine::FeedbackNotEnoughSpaceRuleList& CFeedbackNotEnoughSpaceDlg::GetRules() const
+{
+	return m_feedbackRules;
+}
+
 void CFeedbackNotEnoughSpaceDlg::DoDataExchange(CDataExchange* pDX)
 {
 	CLanguageDialog::DoDataExchange(pDX);
Index: src/ch/FeedbackNotEnoughSpaceDlg.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackNotEnoughSpaceDlg.h	(.../FeedbackNotEnoughSpaceDlg.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/ch/FeedbackNotEnoughSpaceDlg.h	(.../FeedbackNotEnoughSpaceDlg.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -20,45 +20,45 @@
 #define __FEEDBACKNOTENOUGHSPACEDLG_H__
 
 #include "../libchengine/TLocalFilesystem.h"
+#include "../libchengine/FeedbackNotEnoughSpaceRuleList.h"
 
 /////////////////////////////////////////////////////////////////////////////
 // CFeedbackNotEnoughSpaceDlg dialog
 
 class CFeedbackNotEnoughSpaceDlg : public ictranslate::CLanguageDialog
 {
-// Construction
 public:
 	CFeedbackNotEnoughSpaceDlg(unsigned long long ullSizeRequired, const wchar_t* pszSrcPath, const wchar_t* pszDstPath);   // standard constructor
 
-// Overrides
-protected:
-	void DoDataExchange(CDataExchange* pDX) override;    // DDX/DDV support
+	bool IsApplyToAllItemsChecked() const;
 
-// Implementation
-public:
-	CString	m_strDisk;
-	unsigned long long m_ullRequired;
-	std::vector<std::wstring> m_vstrFiles;
-	CListBox	m_ctlFiles;
+	const chengine::FeedbackNotEnoughSpaceRuleList& GetRules() const;
 
 protected:
+	void DoDataExchange(CDataExchange* pDX) override;    // DDX/DDV support
 	void UpdateDialog();
 	void OnLanguageChanged() override;
 	void OnCancel() override;
 
 	BOOL OnInitDialog() override;
+
 	afx_msg void OnTimer(UINT_PTR nIDEvent);
 	afx_msg void OnRetryButton();
 	afx_msg void OnIgnoreButton();
 	afx_msg void OnBnClickedCancel();
 
 	DECLARE_MESSAGE_MAP()
 
-public:
-	BOOL m_bAllItems;
-
 private:
+	BOOL m_bAllItems = FALSE;
+	CString m_strDisk;
+	unsigned long long m_ullRequired = 0;
+	std::vector<std::wstring> m_vstrFiles;
+
+	CListBox m_ctlFiles;
+
 	chengine::TLocalFilesystem m_fsLocal;
+	chengine::FeedbackNotEnoughSpaceRuleList m_feedbackRules;	// feedback rules resulting from choices made in this dialog box
 };
 
 #endif
Index: src/ch/FeedbackReplaceDlg.cpp
===================================================================
diff -u -r5b4b933c78513d867ec02d33325907c2069c7bef -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackReplaceDlg.cpp	(.../FeedbackReplaceDlg.cpp)	(revision 5b4b933c78513d867ec02d33325907c2069c7bef)
+++ src/ch/FeedbackReplaceDlg.cpp	(.../FeedbackReplaceDlg.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -9,14 +9,14 @@
 #include "resource.h"
 #include "../libchengine/TFileInfo.h"
 #include "StringHelpers.h"
+#include "../libchengine/FeedbackPredefinedRules.h"
 
-// CFeedbackReplaceDlg dialog
+using namespace chengine;
 
 IMPLEMENT_DYNAMIC(CFeedbackReplaceDlg, ictranslate::CLanguageDialog)
 
 CFeedbackReplaceDlg::CFeedbackReplaceDlg(const chengine::TFileInfo& spSrcFile, const chengine::TFileInfo& spDstFile, CWnd* pParent /*=nullptr*/)
 	: ictranslate::CLanguageDialog(IDD_FEEDBACK_REPLACE_DIALOG, pParent),
-	m_bAllItems(FALSE),
 	m_rSrcFile(spSrcFile),
 	m_rDstFile(spDstFile)
 {
@@ -231,92 +231,80 @@
 
 void CFeedbackReplaceDlg::OnBnMassReplace()
 {
-	CString str;
 	switch (m_btnMassReplace.m_nMenuResult)
 	{
 	case ID_FEEDBACK_REPLACE_ALLEXISTINGFILES:
-		str = L"Replace all existing files";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_ApplyToAll, eResult_Overwrite);
 		break;
 	case ID_FEEDBACK_REPLACE_FILESWITHDIFFERENTDATESORSIZES:
-		str = L"Replace files with different dates or sizes";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenDifferentDateOrSize, eResult_Overwrite);
 		break;
 	case ID_FEEDBACK_REPLACE_OLDERFILESWITHNEWERVERSIONS:
-		str = L"Replace older files with newer ones";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenNewerThanDst, eResult_Overwrite);
 		break;
 	case ID_FEEDBACK_REPLACE_NEWERFILESWITHOLDERVERSIONS:
-		str = L"Replace newer files with older ones";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenOlderThanDst, eResult_Overwrite);
 		break;
-	default:
-		str = L"Default";
-		break;
 	}
-	MessageBox(str);
+
+	EndDialog(chengine::EFeedbackResult::eResult_Overwrite);
 }
 
 void CFeedbackReplaceDlg::OnBnMassRename()
 {
-	CString str;
 	switch (m_btnMassRename.m_nMenuResult)
 	{
 	case ID_FEEDBACK_RENAME_WHENDESTIONATIONFILEEXISTS:
-		str = L"Rename when destination file exists";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_ApplyToAll, eResult_Rename);
 		break;
 	case ID_FEEDBACK_RENAME_WHENDATEORSIZEDIFFERS:
-		str = L"Rename when size or date differs";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenDifferentDateOrSize, eResult_Rename);
 		break;
 	case ID_FEEDBACK_RENAME_WHENDATEANDSZEARESAME:
-		str = L"Rename when date and size are same";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenSameDateAndSize, eResult_Rename);
 		break;
 	case ID_FEEDBACK_RENAME_WHENNEWERTHANDESTINATION:
-		str = L"Rename when newer than destination";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenNewerThanDst, eResult_Rename);
 		break;
 	case ID_FEEDBACK_RENAME_WHENOLDERTHANDESTINATION:
-		str = L"Rename when older than destination";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenOlderThanDst, eResult_Rename);
 		break;
-	default:
-		str = L"Default";
-		break;
 	}
-	MessageBox(str);
+
+	EndDialog(chengine::EFeedbackResult::eResult_Rename);
 }
 
 void CFeedbackReplaceDlg::OnBnMassResume()
 {
-	CString str;
 	switch (m_btnMassResume.m_nMenuResult)
 	{
 	case ID_FEEDBACK_RESUME_WHENFILEBIGGERTHANDESTINATION:
-		str = L"Resume when file is bigger than destination";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenBiggerThanDst, eResult_CopyRest);
 		break;
-	default:
-		str = L"Default";
-		break;
 	}
-	MessageBox(str);
+
+	EndDialog(chengine::EFeedbackResult::eResult_CopyRest);
 }
 
 void CFeedbackReplaceDlg::OnBnMassSkip()
 {
-	CString str;
 	switch (m_btnMassSkip.m_nMenuResult)
 	{
 	case ID_FEEDBACK_SKIP_ALLEXISTINGDESTINATIONFILES:
-		str = L"Skip all files already existing in destination dir";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_ApplyToAll, eResult_Skip);
 		break;
 	case ID_FEEDBACK_SKIP_ALLFILESWITHSAMEDATESANDSIZES:
-		str = L"Skip files with same date and size";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenSameDateAndSize, eResult_Skip);
 		break;
 	case ID_FEEDBACK_SKIP_FILESTHATAREOLDERTHANDESTINATION:
-		str = L"Skip files that are older than existing destination";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenOlderThanDst, eResult_Skip);
 		break;
 	case ID_FEEDBACK_SKIP_FILESTHATARENEWERTHANDESTINATION:
-		str = L"Skip files that are newer than destination";
+		m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenNewerThanDst, eResult_Skip);
 		break;
-	default:
-		str = L"Default";
-		break;
 	}
-	MessageBox(str);
+
+	EndDialog(chengine::EFeedbackResult::eResult_Skip);
 }
 
 void CFeedbackReplaceDlg::OnCancel()
@@ -325,9 +313,9 @@
 	EndDialog(chengine::EFeedbackResult::eResult_Cancel);
 }
 
-bool CFeedbackReplaceDlg::IsApplyToAllItemsChecked() const
+const chengine::FeedbackAlreadyExistsRuleList& CFeedbackReplaceDlg::GetRules() const
 {
-	return m_bAllItems != FALSE;
+	return m_feedbackRules;
 }
 
 void CFeedbackReplaceDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
Index: src/ch/FeedbackReplaceDlg.h
===================================================================
diff -u -r5b4b933c78513d867ec02d33325907c2069c7bef -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/ch/FeedbackReplaceDlg.h	(.../FeedbackReplaceDlg.h)	(revision 5b4b933c78513d867ec02d33325907c2069c7bef)
+++ src/ch/FeedbackReplaceDlg.h	(.../FeedbackReplaceDlg.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -19,6 +19,8 @@
 #ifndef __FEEDBACKREPLACEDLG_H__
 #define __FEEDBACKREPLACEDLG_H__
 
+#include "../libchengine/FeedbackAlreadyExistsRuleList.h"
+
 namespace chengine
 {
 	class TFileInfo;
@@ -34,7 +36,7 @@
 
 	BOOL OnInitDialog() override;
 
-	bool IsApplyToAllItemsChecked() const;
+	const chengine::FeedbackAlreadyExistsRuleList& GetRules() const;
 
 protected:
 	void DoDataExchange(CDataExchange* pDX) override;    // DDX/DDV support
@@ -43,6 +45,19 @@
 	void RefreshFilesInfo();
 	void RefreshImages();
 
+	afx_msg void OnBnClickedReplaceButton();
+	afx_msg void OnBnClickedCopyRestButton();
+	afx_msg void OnBnClickedSkipButton();
+	afx_msg void OnBnClickedPauseButton();
+	afx_msg void OnBnClickedCancelButton();
+
+	afx_msg void OnBnMassReplace();
+	afx_msg void OnBnMassRename();
+	afx_msg void OnBnMassResume();
+	afx_msg void OnBnMassSkip();
+
+	afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
+
 	DECLARE_MESSAGE_MAP()
 
 private:
@@ -76,27 +91,12 @@
 	CMFCMenuButton m_btnMassResume;
 	CMFCMenuButton m_btnMassSkip;
 
-	BOOL m_bAllItems;
-
 	CRect m_rcInitial;
 
-protected:
 	const chengine::TFileInfo& m_rSrcFile;
 	const chengine::TFileInfo& m_rDstFile;
 
-public:
-	afx_msg void OnBnClickedReplaceButton();
-	afx_msg void OnBnClickedCopyRestButton();
-	afx_msg void OnBnClickedSkipButton();
-	afx_msg void OnBnClickedPauseButton();
-	afx_msg void OnBnClickedCancelButton();
-
-	afx_msg void OnBnMassReplace();
-	afx_msg void OnBnMassRename();
-	afx_msg void OnBnMassResume();
-	afx_msg void OnBnMassSkip();
-
-	afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
+	chengine::FeedbackAlreadyExistsRuleList m_feedbackRules;	// feedback rules resulting from choices made in this dialog box
 };
 
 #endif
Index: src/libchengine/ECompareType.h
===================================================================
diff -u -rf3c80778cfee0736195e00274c78040f7908ac5b -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/ECompareType.h	(.../ECompareType.h)	(revision f3c80778cfee0736195e00274c78040f7908ac5b)
+++ src/libchengine/ECompareType.h	(.../ECompareType.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -8,7 +8,8 @@
 		eCmp_LessOrEqual = 1,
 		eCmp_Equal = 2,
 		eCmp_GreaterOrEqual = 3,
-		eCmp_Greater = 4
+		eCmp_Greater = 4,
+		eCmp_NotEqual = 5
 	};
 
 	template<class T>
@@ -26,6 +27,8 @@
 			return value1 >= value2;
 		case eCmp_Greater:
 			return value1 > value2;
+		case eCmp_NotEqual:
+			return value1 != value2;
 		}
 
 		throw std::runtime_error("Invalid compare type");
Index: src/libchengine/EFeedbackResult.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/EFeedbackResult.h	(.../EFeedbackResult.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/EFeedbackResult.h	(.../EFeedbackResult.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -30,7 +30,8 @@
 		eResult_Cancel,
 		eResult_Pause,
 		eResult_Retry,
-		eResult_Ignore
+		eResult_Ignore,
+		eResult_Rename
 	};
 }
 
Index: src/libchengine/EFileError.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/EFileError.h	(.../EFileError.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/EFileError.h	(.../EFileError.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -21,7 +21,7 @@
 
 namespace chengine
 {
-	enum class EFileError
+	enum EFileError
 	{
 		eDeleteError,		///< Problem occurred when tried to delete the fs object
 		eSeekError,			///< Problem occurred when tried to set file pointer
Index: src/libchengine/EOperationEvent.h
===================================================================
diff -u
--- src/libchengine/EOperationEvent.h	(revision 0)
+++ src/libchengine/EOperationEvent.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace chengine
+{
+	enum EOperationEvent
+	{
+		eOperationEvent_Finished,
+		eOperationEvent_Error
+	};
+}
Index: src/libchengine/FeedbackAlreadyExistsRule.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackAlreadyExistsRule.cpp	(revision 0)
+++ src/libchengine/FeedbackAlreadyExistsRule.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,369 @@
+#include "stdafx.h"
+#include "FeedbackAlreadyExistsRule.h"
+#include "../libstring/TString.h"
+#include "../libstring/TStringArray.h"
+
+using namespace serializer;
+using namespace string;
+
+namespace chengine
+{
+	FeedbackAlreadyExistsRule::FeedbackAlreadyExistsRule() :
+		m_bUseMask(m_setModifications, false),
+		m_spaMask(m_setModifications),
+		m_bUseExcludeMask(m_setModifications, false),
+		m_spaExcludeMask(m_setModifications),
+		m_bUseDateCompare(m_setModifications, false),
+		m_cmpLastModified(m_setModifications, eCmp_Equal),
+		m_bUseSizeCompare(m_setModifications, false),
+		m_cmpSize(m_setModifications, eCmp_Equal),
+		m_eResult(m_setModifications, eResult_Unknown)
+	{
+		m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_Added] = true;
+	}
+
+
+	FeedbackAlreadyExistsRule::FeedbackAlreadyExistsRule(const FeedbackAlreadyExistsRule& rSrc) :
+		serializer::SerializableObject<FeedbackAlreadyExistsRuleEnum::eMod_Last>(rSrc),
+		m_bUseMask(rSrc.m_bUseMask, m_setModifications),
+		m_spaMask(rSrc.m_spaMask, m_setModifications),
+		m_bUseExcludeMask(rSrc.m_bUseExcludeMask, m_setModifications),
+		m_spaExcludeMask(rSrc.m_spaExcludeMask, m_setModifications),
+		m_bUseDateCompare(rSrc.m_bUseDateCompare, m_setModifications),
+		m_cmpLastModified(rSrc.m_cmpLastModified, m_setModifications),
+		m_bUseSizeCompare(rSrc.m_bUseSizeCompare, m_setModifications),
+		m_cmpSize(rSrc.m_cmpSize, m_setModifications),
+		m_eResult(rSrc.m_eResult, m_setModifications)
+	{
+	}
+
+	FeedbackAlreadyExistsRule& FeedbackAlreadyExistsRule::operator=(const FeedbackAlreadyExistsRule& rSrc)
+	{
+		if(this == &rSrc)
+			return *this;
+
+		__super::operator=(rSrc);
+
+		SetData(rSrc);
+
+		return *this;
+	}
+
+	bool FeedbackAlreadyExistsRule::operator==(const FeedbackAlreadyExistsRule& rSrc) const
+	{
+		if(m_bUseMask != rSrc.m_bUseMask)
+			return false;
+		if(m_spaMask != rSrc.m_spaMask)
+			return false;
+
+		if(m_bUseExcludeMask != rSrc.m_bUseExcludeMask)
+			return false;
+
+		if(m_spaExcludeMask != rSrc.m_spaExcludeMask)
+			return false;
+
+		if(m_bUseDateCompare != rSrc.m_bUseDateCompare)
+			return false;
+		if(m_cmpLastModified != rSrc.m_cmpLastModified)
+			return false;
+
+		if(m_bUseSizeCompare != rSrc.m_bUseSizeCompare)
+			return false;
+		if(m_cmpSize != rSrc.m_cmpSize)
+			return false;
+
+		if(m_eResult != rSrc.m_eResult)
+			return false;
+
+		return true;
+	}
+
+	bool FeedbackAlreadyExistsRule::operator!=(const FeedbackAlreadyExistsRule& rSrc) const
+	{
+		return !operator==(rSrc);
+	}
+
+	void FeedbackAlreadyExistsRule::SetData(const FeedbackAlreadyExistsRule& rSrc)
+	{
+		if(this == &rSrc)
+			return;
+
+		m_bUseMask = rSrc.m_bUseMask;
+		m_spaMask = rSrc.m_spaMask;
+		m_bUseExcludeMask = rSrc.m_bUseExcludeMask;
+		m_spaExcludeMask = rSrc.m_spaExcludeMask;
+		m_bUseDateCompare = rSrc.m_bUseDateCompare;
+		m_cmpLastModified = rSrc.m_cmpLastModified;
+		m_bUseSizeCompare = rSrc.m_bUseSizeCompare;
+		m_cmpSize = rSrc.m_cmpSize;
+		m_eResult = rSrc.m_eResult;
+	}
+
+	bool FeedbackAlreadyExistsRule::Matches(const TFileInfo& rSrcFile, const TFileInfo& rDstFile, EFeedbackResult& eResult) const
+	{
+		eResult = eResult_Unknown;
+
+		if(m_bUseMask)
+		{
+			if(!m_spaMask.Get().MatchesAny(rDstFile.GetFullFilePath().GetFileName().ToString()))
+				return false;
+		}
+		if(m_bUseExcludeMask)
+		{
+			if(m_spaExcludeMask.Get().MatchesAny(rDstFile.GetFullFilePath().GetFileName().ToString()))
+				return false;
+		}
+		if(m_bUseDateCompare)
+		{
+			if(!CompareByType(rSrcFile.GetLastWriteTime(), rDstFile.GetLastWriteTime(), m_cmpLastModified))
+				return false;
+		}
+
+		if(m_bUseSizeCompare)
+		{
+			if(!CompareByType(rSrcFile.GetLength64(), rDstFile.GetLength64(), m_cmpSize))
+				return false;
+		}
+
+		eResult = m_eResult;
+		return true;
+	}
+
+	void FeedbackAlreadyExistsRule::InitColumns(serializer::IColumnsDefinition& rColumns)
+	{
+		rColumns.AddColumn(_T("id"), ColumnType<object_id_t>::value);
+		rColumns.AddColumn(_T("use_mask"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("mask"), IColumnsDefinition::eType_string);
+		rColumns.AddColumn(_T("use_exclude_mask"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("exclude_mask"), IColumnsDefinition::eType_string);
+		rColumns.AddColumn(_T("use_date_compare"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("date_compare_type"), IColumnsDefinition::eType_int);
+		rColumns.AddColumn(_T("use_size_compare"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("size_compare_type"), IColumnsDefinition::eType_int);
+		rColumns.AddColumn(_T("result"), IColumnsDefinition::eType_int);
+	}
+
+	void FeedbackAlreadyExistsRule::Store(const ISerializerContainerPtr& spContainer) const
+	{
+		bool bAdded = m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_Added];
+		if(m_setModifications.any())
+		{
+			ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, bAdded);
+
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_UseMask])
+				rRow.SetValue(_T("use_mask"), m_bUseMask);
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_Mask])
+				rRow.SetValue(_T("mask"), GetCombinedMask());
+
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_UseExcludeMask])
+				rRow.SetValue(_T("use_exclude_mask"), m_bUseExcludeMask);
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_ExcludeMask])
+				rRow.SetValue(_T("exclude_mask"), GetCombinedExcludeMask());
+
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_UseDateCompare])
+				rRow.SetValue(_T("use_date_compare"), m_bUseDateCompare);
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_DateCompare])
+				rRow.SetValue(_T("date_compare_type"), m_cmpLastModified);
+
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_UseSizeCompare])
+				rRow.SetValue(_T("use_size_compare"), m_bUseSizeCompare);
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_SizeCompare])
+				rRow.SetValue(_T("size_compare_type"), m_cmpSize);
+
+			if(bAdded || m_setModifications[FeedbackAlreadyExistsRuleEnum::eMod_Result])
+				rRow.SetValue(_T("result"), m_eResult);
+
+			m_setModifications.reset();
+		}
+	}
+
+	void FeedbackAlreadyExistsRule::Load(const ISerializerRowReaderPtr& spRowReader)
+	{
+		TString strMask;
+
+		spRowReader->GetValue(_T("use_mask"), m_bUseMask.Modify());
+		spRowReader->GetValue(_T("mask"), strMask);
+		SetCombinedMask(strMask);
+
+		spRowReader->GetValue(_T("use_exclude_mask"), m_bUseExcludeMask.Modify());
+		spRowReader->GetValue(_T("exclude_mask"), strMask);
+		SetCombinedExcludeMask(strMask);
+
+		spRowReader->GetValue(_T("use_date_compare"), m_bUseDateCompare.Modify());
+		spRowReader->GetValue(_T("date_compare_type"), *(int*)&m_cmpLastModified.Modify());
+
+		spRowReader->GetValue(_T("use_size_compare"), m_bUseSizeCompare.Modify());
+		spRowReader->GetValue(_T("size_compare_type"), *(int*)&m_cmpSize.Modify());
+
+		spRowReader->GetValue(_T("result"), *(int*)&m_eResult.Modify());
+
+		m_setModifications.reset();
+	}
+
+	void FeedbackAlreadyExistsRule::StoreInConfig(TConfig& rConfig) const
+	{
+		SetConfigValue(rConfig, _T("IncludeMask.Use"), m_bUseMask.Get());
+		SetConfigValue(rConfig, _T("IncludeMask.MaskList.Mask"), m_spaMask.Get().ToSerializedStringArray());
+
+		SetConfigValue(rConfig, _T("ExcludeMask.Use"), m_bUseExcludeMask.Get());
+		SetConfigValue(rConfig, _T("ExcludeMask.MaskList.Mask"), m_spaExcludeMask.Get().ToSerializedStringArray());
+
+		SetConfigValue(rConfig, _T("DateCompare.Use"), m_bUseDateCompare.Get());
+		SetConfigValue(rConfig, _T("DateCompare.CompareType"), m_cmpLastModified.Get());
+
+		SetConfigValue(rConfig, _T("SizeCompare.Use"), m_bUseDateCompare.Get());
+		SetConfigValue(rConfig, _T("SizeCompare.CompareType"), m_cmpLastModified.Get());
+
+		SetConfigValue(rConfig, _T("Result"), m_eResult.Get());
+	}
+
+	void FeedbackAlreadyExistsRule::ReadFromConfig(const TConfig& rConfig)
+	{
+		if(!GetConfigValue(rConfig, _T("IncludeMask.Use"), m_bUseMask.Modify()))
+			m_bUseMask = false;
+
+		TStringArray arrMask;
+		m_spaMask.Modify().Clear();
+		GetConfigValue(rConfig, _T("IncludeMask.MaskList.Mask"), arrMask);
+		m_spaMask.Modify().FromSerializedStringArray(arrMask);
+
+		if(!GetConfigValue(rConfig, _T("ExcludeMask.Use"), m_bUseExcludeMask.Modify()))
+			m_bUseExcludeMask = false;
+
+		m_spaExcludeMask.Modify().Clear();
+		GetConfigValue(rConfig, _T("ExcludeMask.MaskList.Mask"), arrMask);
+		m_spaExcludeMask.Modify().FromSerializedStringArray(arrMask);
+
+		if(!GetConfigValue(rConfig, _T("DateCompare.Use"), m_bUseDateCompare.Modify()))
+			m_bUseDateCompare = false;
+		if(!GetConfigValue(rConfig, _T("DateCompare.CompareType"), *(int*)m_cmpLastModified.Modify()))
+			m_cmpLastModified = eCmp_Equal;
+
+		if(!GetConfigValue(rConfig, _T("SizeCompare.Use"), m_bUseSizeCompare.Modify()))
+			m_bUseSizeCompare = false;
+		if(!GetConfigValue(rConfig, _T("SizeCompare.CompareType"), *(int*)m_cmpSize.Modify()))
+			m_cmpSize = eCmp_Equal;
+
+		if(!GetConfigValue(rConfig, _T("Result"), *(int*)m_eResult.Modify()))
+			m_eResult = eResult_Unknown;
+	}
+
+	bool FeedbackAlreadyExistsRule::HaveSameCondition(const FeedbackAlreadyExistsRule& rSrc) const
+	{
+		if(m_bUseMask != rSrc.m_bUseMask)
+			return false;
+		else if(m_bUseMask == true && m_spaMask != rSrc.m_spaMask)
+			return false;
+
+		if(m_bUseExcludeMask != rSrc.m_bUseExcludeMask)
+			return false;
+		else if(m_bUseExcludeMask == true && m_spaExcludeMask != rSrc.m_spaExcludeMask)
+			return false;
+
+		if(m_bUseDateCompare != rSrc.m_bUseDateCompare)
+			return false;
+		else if(m_bUseDateCompare == true && m_cmpLastModified != rSrc.m_cmpLastModified)
+			return false;
+
+		if(m_bUseSizeCompare != rSrc.m_bUseSizeCompare)
+			return false;
+		else if(m_bUseSizeCompare == true && m_cmpSize != rSrc.m_cmpSize)
+			return false;
+
+		return true;
+	}
+
+	void FeedbackAlreadyExistsRule::SetUseMask(bool bUseMask)
+	{
+		m_bUseMask = bUseMask;
+	}
+
+	bool FeedbackAlreadyExistsRule::GetUseMask() const
+	{
+		return m_bUseMask;
+	}
+
+	bool FeedbackAlreadyExistsRule::GetUseExcludeMask() const
+	{
+		return m_bUseExcludeMask;
+	}
+
+	void FeedbackAlreadyExistsRule::SetUseExcludeMask(bool bUseExcludeMask)
+	{
+		m_bUseExcludeMask = bUseExcludeMask;
+	}
+
+	bool FeedbackAlreadyExistsRule::GetUseDateCompare() const
+	{
+		return m_bUseDateCompare;
+	}
+
+	void FeedbackAlreadyExistsRule::SetUseDateCompare(bool bUseDateCompare)
+	{
+		m_bUseDateCompare = bUseDateCompare;
+	}
+
+	ECompareType FeedbackAlreadyExistsRule::GetDateCompareType() const
+	{
+		return m_cmpLastModified;
+	}
+
+	void FeedbackAlreadyExistsRule::SetDateCompareType(ECompareType eCmpType)
+	{
+		m_cmpLastModified = eCmpType;
+	}
+
+	bool FeedbackAlreadyExistsRule::GetUseSizeCompare() const
+	{
+		return m_bUseSizeCompare;
+	}
+
+	void FeedbackAlreadyExistsRule::SetUseSizeCompare(bool bUseSizeCompare)
+	{
+		m_bUseSizeCompare = bUseSizeCompare;
+	}
+
+	ECompareType FeedbackAlreadyExistsRule::GetSizeCompareType() const
+	{
+		return m_cmpSize;
+	}
+
+	void FeedbackAlreadyExistsRule::SetSizeCompareType(ECompareType eCmpType)
+	{
+		m_cmpSize = eCmpType;
+	}
+
+	TString FeedbackAlreadyExistsRule::GetCombinedMask() const
+	{
+		return m_spaMask.Get().ToString();
+	}
+
+	void FeedbackAlreadyExistsRule::SetCombinedMask(const TString& strMask)
+	{
+		TStringPatternArray& rPatterns = m_spaMask.Modify();
+		rPatterns.Clear();
+		rPatterns.FromString(strMask);
+	}
+
+	TString FeedbackAlreadyExistsRule::GetCombinedExcludeMask() const
+	{
+		return m_spaExcludeMask.Get().ToString();
+	}
+
+	void FeedbackAlreadyExistsRule::SetCombinedExcludeMask(const TString& strMask)
+	{
+		TStringPatternArray& rPatterns = m_spaExcludeMask.Modify();
+		rPatterns.Clear();
+		rPatterns.FromString(strMask);
+	}
+
+	chengine::EFeedbackResult FeedbackAlreadyExistsRule::GetResult() const
+	{
+		return m_eResult;
+	}
+
+	void FeedbackAlreadyExistsRule::SetResult(EFeedbackResult eResult)
+	{
+		m_eResult = eResult;
+	}
+}
Index: src/libchengine/FeedbackAlreadyExistsRule.h
===================================================================
diff -u
--- src/libchengine/FeedbackAlreadyExistsRule.h	(revision 0)
+++ src/libchengine/FeedbackAlreadyExistsRule.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,104 @@
+#pragma once
+
+#include "libchengine.h"
+#include "../libserializer/SerializableObject.h"
+#include "../libstring/TStringPatternArray.h"
+#include "ECompareType.h"
+#include "EFeedbackResult.h"
+#include "../libserializer/SerializerDataTypes.h"
+#include <bitset>
+#include "../libserializer/TSharedModificationTracker.h"
+#include "TFileInfo.h"
+#include "TConfig.h"
+
+namespace chengine
+{
+	namespace FeedbackAlreadyExistsRuleEnum
+	{
+		enum EModifications
+		{
+			eMod_Added,
+			eMod_UseMask,
+			eMod_Mask,
+			eMod_UseExcludeMask,
+			eMod_ExcludeMask,
+			eMod_UseSizeCompare,
+			eMod_SizeCompare,
+			eMod_UseDateCompare,
+			eMod_DateCompare,
+			eMod_Result,
+
+			eMod_Last
+		};
+	}
+
+#pragma warning(push)
+#pragma warning(disable: 4251)
+	class LIBCHENGINE_API FeedbackAlreadyExistsRule : public serializer::SerializableObject<FeedbackAlreadyExistsRuleEnum::eMod_Last>
+	{
+	public:
+		FeedbackAlreadyExistsRule();
+		FeedbackAlreadyExistsRule(const FeedbackAlreadyExistsRule& rSrc);
+		FeedbackAlreadyExistsRule& operator=(const FeedbackAlreadyExistsRule& rSrc);
+
+		bool operator==(const FeedbackAlreadyExistsRule& rSrc) const;
+		bool operator!=(const FeedbackAlreadyExistsRule& rSrc) const;
+
+		void SetData(const FeedbackAlreadyExistsRule& rSrc);
+
+		bool Matches(const TFileInfo& rSrcFile, const TFileInfo& rDstFile, EFeedbackResult& eResult) const;
+
+		void Store(const serializer::ISerializerContainerPtr& spContainer) const override;
+		void Load(const serializer::ISerializerRowReaderPtr& spRowReader) override;
+		static void InitColumns(serializer::IColumnsDefinition& rColumns);
+
+		void StoreInConfig(TConfig& rConfig) const;
+		void ReadFromConfig(const TConfig& rConfig);
+
+		// comparison
+		bool HaveSameCondition(const FeedbackAlreadyExistsRule& rSrc) const;
+
+		// get/set
+		// atrributes access
+		bool GetUseMask() const;
+		void SetUseMask(bool bUseMask);
+
+		string::TString GetCombinedMask() const;
+		void SetCombinedMask(const string::TString& strMask);
+
+		bool GetUseExcludeMask() const;
+		void SetUseExcludeMask(bool bUseExcludeMask);
+
+		string::TString GetCombinedExcludeMask() const;
+		void SetCombinedExcludeMask(const string::TString& strMask);
+
+		bool GetUseDateCompare() const;
+		void SetUseDateCompare(bool bUseDateCompare);
+
+		ECompareType GetDateCompareType() const;
+		void SetDateCompareType(ECompareType eCmpType);
+		
+		bool GetUseSizeCompare() const;
+		void SetUseSizeCompare(bool bUseSizeCompare);
+
+		ECompareType GetSizeCompareType() const;
+		void SetSizeCompareType(ECompareType eCmpType);
+
+		EFeedbackResult GetResult() const;
+		void SetResult(EFeedbackResult eResult);
+
+	private:
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_UseMask> m_bUseMask;
+		serializer::TSharedModificationTracker<string::TStringPatternArray, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_Mask> m_spaMask;
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_UseExcludeMask> m_bUseExcludeMask;
+		serializer::TSharedModificationTracker<string::TStringPatternArray, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_ExcludeMask> m_spaExcludeMask;
+
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_UseDateCompare> m_bUseDateCompare;
+		serializer::TSharedModificationTracker<ECompareType, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_DateCompare> m_cmpLastModified;
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_UseSizeCompare> m_bUseSizeCompare;
+		serializer::TSharedModificationTracker<ECompareType, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_SizeCompare> m_cmpSize;
+
+		serializer::TSharedModificationTracker<EFeedbackResult, Bitset, FeedbackAlreadyExistsRuleEnum::eMod_Result> m_eResult;
+	};
+#pragma warning(pop)
+}
Index: src/libchengine/FeedbackAlreadyExistsRuleList.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackAlreadyExistsRuleList.cpp	(revision 0)
+++ src/libchengine/FeedbackAlreadyExistsRuleList.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,90 @@
+#include "stdafx.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+#include "TConfigArray.h"
+#include "../libserializer/IColumnsDefinition.h"
+#include "TFileFilter.h"
+
+using namespace string;
+using namespace serializer;
+
+namespace chengine
+{
+	EFeedbackResult FeedbackAlreadyExistsRuleList::Matches(const TFileInfo& rSrcFile, const TFileInfo& rDstFile) const
+	{
+		if(m_vEntries.empty())
+			return eResult_Unknown;
+
+		for(const FeedbackAlreadyExistsRule& rRule : m_vEntries)
+		{
+			EFeedbackResult eResult = eResult_Unknown;
+			if(rRule.Matches(rSrcFile, rDstFile, eResult))
+				return eResult;
+		}
+
+		return eResult_Unknown;
+	}
+
+	void FeedbackAlreadyExistsRuleList::Merge(const FeedbackAlreadyExistsRuleList& rSrc)
+	{
+		for(size_t stIndex = 0; stIndex < rSrc.GetCount(); ++stIndex)
+		{
+			InsertOrUpdateRule(rSrc.GetAt(stIndex));
+		}
+	}
+
+	void FeedbackAlreadyExistsRuleList::InsertOrUpdateRule(const FeedbackAlreadyExistsRule& rRule)
+	{
+		bool bFound = false;
+		for(size_t stIndex = 0; stIndex < GetCount(); ++stIndex)
+		{
+			FeedbackAlreadyExistsRule& rCurrent = GetAt(stIndex);
+			if(rCurrent.HaveSameCondition(rRule))
+			{
+				bFound = true;
+				rCurrent.SetResult(rRule.GetResult());
+			}
+		}
+
+		if(!bFound)
+			InsertAt(0, rRule);
+	}
+
+	void FeedbackAlreadyExistsRuleList::InitColumns(const serializer::ISerializerContainerPtr& spContainer) const
+	{
+		IColumnsDefinition& rColumns = spContainer->GetColumnsDefinition();
+		if(rColumns.IsEmpty())
+			TFileFilter::InitColumns(rColumns);
+	}
+
+	void FeedbackAlreadyExistsRuleList::StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const
+	{
+		rConfig.DeleteNode(pszNodeName);
+		for(const FeedbackAlreadyExistsRule& rRule : m_vEntries)
+		{
+			TConfig cfgNode;
+			rRule.StoreInConfig(cfgNode);
+
+			TString strNode = TString(pszNodeName) + _T(".RuleDefinition");
+			rConfig.AddSubConfig(strNode.c_str(), cfgNode);
+		}
+	}
+
+	bool FeedbackAlreadyExistsRuleList::ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName)
+	{
+		m_vEntries.clear();
+
+		TConfigArray vConfigs;
+		if(!rConfig.ExtractMultiSubConfigs(pszNodeName, vConfigs))
+			return false;
+
+		for(size_t stIndex = 0; stIndex < vConfigs.GetCount(); ++stIndex)
+		{
+			const TConfig& rCfg = vConfigs.GetAt(stIndex);
+			FeedbackAlreadyExistsRule rule;
+			rule.ReadFromConfig(rCfg);
+
+			m_vEntries.push_back(rule);
+		}
+		return true;
+	}
+}
Index: src/libchengine/FeedbackAlreadyExistsRuleList.h
===================================================================
diff -u
--- src/libchengine/FeedbackAlreadyExistsRuleList.h	(revision 0)
+++ src/libchengine/FeedbackAlreadyExistsRuleList.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "libchengine.h"
+#include "FeedbackAlreadyExistsRule.h"
+#include "TConfig.h"
+#include "../libserializer/SerializableContainer.h"
+
+namespace chengine
+{
+#pragma warning(push)
+#pragma warning(disable: 4251)
+
+	class LIBCHENGINE_API FeedbackAlreadyExistsRuleList : public serializer::SerializableContainer<FeedbackAlreadyExistsRule>
+	{
+	public:
+		EFeedbackResult Matches(const TFileInfo& rSrcFile, const TFileInfo& rDstFile) const;
+
+		void Merge(const FeedbackAlreadyExistsRuleList& rSrc);
+
+		void InitColumns(const serializer::ISerializerContainerPtr& spContainer) const override;
+
+		void StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const;
+		bool ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName);
+
+	private:
+		void InsertOrUpdateRule(const FeedbackAlreadyExistsRule& rRule);
+	};
+#pragma warning(pop)
+}
+
+CONFIG_MEMBER_SERIALIZATION(FeedbackAlreadyExistsRuleList)
Index: src/libchengine/FeedbackErrorRule.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackErrorRule.cpp	(revision 0)
+++ src/libchengine/FeedbackErrorRule.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,372 @@
+#include "stdafx.h"
+#include "FeedbackErrorRule.h"
+#include "../libstring/TString.h"
+#include "../libstring/TStringArray.h"
+#include "../libchcore/TPath.h"
+
+using namespace serializer;
+using namespace string;
+using namespace chcore;
+
+namespace chengine
+{
+	FeedbackErrorRule::FeedbackErrorRule() :
+		m_bUseMask(m_setModifications, false),
+		m_spaMask(m_setModifications),
+		m_bUseExcludeMask(m_setModifications, false),
+		m_spaExcludeMask(m_setModifications),
+		m_bUseErrorType(m_setModifications, false),
+		m_eErrorType(m_setModifications, EFileError::eDeleteError),
+		m_bUseSystemErrorNo(m_setModifications, false),
+		m_ulSystemErrorNo(m_setModifications, 0),
+		m_eResult(m_setModifications, eResult_Unknown)
+	{
+		m_setModifications[FeedbackErrorRuleEnum::eMod_Added] = true;
+	}
+
+
+	FeedbackErrorRule::FeedbackErrorRule(const FeedbackErrorRule& rSrc) :
+		serializer::SerializableObject<FeedbackErrorRuleEnum::eMod_Last>(rSrc),
+		m_bUseMask(rSrc.m_bUseMask, m_setModifications),
+		m_spaMask(rSrc.m_spaMask, m_setModifications),
+		m_bUseExcludeMask(rSrc.m_bUseExcludeMask, m_setModifications),
+		m_spaExcludeMask(rSrc.m_spaExcludeMask, m_setModifications),
+		m_bUseErrorType(rSrc.m_bUseErrorType, m_setModifications),
+		m_eErrorType(rSrc.m_eErrorType, m_setModifications),
+		m_bUseSystemErrorNo(rSrc.m_bUseSystemErrorNo, m_setModifications),
+		m_ulSystemErrorNo(rSrc.m_ulSystemErrorNo, m_setModifications),
+		m_eResult(rSrc.m_eResult, m_setModifications)
+	{
+	}
+
+	FeedbackErrorRule& FeedbackErrorRule::operator=(const FeedbackErrorRule& rSrc)
+	{
+		if(this == &rSrc)
+			return *this;
+
+		__super::operator=(rSrc);
+
+		SetData(rSrc);
+
+		return *this;
+	}
+
+	bool FeedbackErrorRule::operator==(const FeedbackErrorRule& rSrc) const
+	{
+		if(m_bUseMask != rSrc.m_bUseMask)
+			return false;
+		if(m_spaMask != rSrc.m_spaMask)
+			return false;
+
+		if(m_bUseExcludeMask != rSrc.m_bUseExcludeMask)
+			return false;
+
+		if(m_spaExcludeMask != rSrc.m_spaExcludeMask)
+			return false;
+
+		if(m_bUseErrorType != rSrc.m_bUseErrorType)
+			return false;
+		if(m_eErrorType != rSrc.m_eErrorType)
+			return false;
+
+		if(m_bUseSystemErrorNo != rSrc.m_bUseSystemErrorNo)
+			return false;
+		if(m_ulSystemErrorNo != rSrc.m_ulSystemErrorNo)
+			return false;
+
+		if(m_eResult != rSrc.m_eResult)
+			return false;
+
+		return true;
+	}
+
+	bool FeedbackErrorRule::operator!=(const FeedbackErrorRule& rSrc) const
+	{
+		return !operator==(rSrc);
+	}
+
+	void FeedbackErrorRule::SetData(const FeedbackErrorRule& rSrc)
+	{
+		if(this == &rSrc)
+			return;
+
+		m_bUseMask = rSrc.m_bUseMask;
+		m_spaMask = rSrc.m_spaMask;
+		m_bUseExcludeMask = rSrc.m_bUseExcludeMask;
+		m_spaExcludeMask = rSrc.m_spaExcludeMask;
+		m_bUseErrorType = rSrc.m_bUseErrorType;
+		m_eErrorType = rSrc.m_eErrorType;
+		m_bUseSystemErrorNo = rSrc.m_bUseSystemErrorNo;
+		m_ulSystemErrorNo = rSrc.m_ulSystemErrorNo;
+		m_eResult = rSrc.m_eResult;
+	}
+
+	bool FeedbackErrorRule::Matches(const string::TString& strSrcPath, const string::TString& /*strDstPath*/, EFileError eErrorType, unsigned long ulError, EFeedbackResult& eResult) const
+	{
+		eResult = eResult_Unknown;
+
+		TSmartPath path = PathFromWString(strSrcPath);
+		if(m_bUseMask)
+		{
+			if(!m_spaMask.Get().MatchesAny(path.GetFileName().ToString()))
+				return false;
+		}
+		if(m_bUseExcludeMask)
+		{
+			if(m_spaExcludeMask.Get().MatchesAny(path.GetFileName().ToString()))
+				return false;
+		}
+		if(m_bUseErrorType)
+		{
+			if(m_eErrorType != eErrorType)
+				return false;
+		}
+
+		if(m_bUseSystemErrorNo)
+		{
+			if(m_ulSystemErrorNo != ulError)
+				return false;
+		}
+
+		eResult = m_eResult;
+		return true;
+	}
+
+	void FeedbackErrorRule::InitColumns(serializer::IColumnsDefinition& rColumns)
+	{
+		rColumns.AddColumn(_T("id"), ColumnType<object_id_t>::value);
+		rColumns.AddColumn(_T("use_mask"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("mask"), IColumnsDefinition::eType_string);
+		rColumns.AddColumn(_T("use_exclude_mask"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("exclude_mask"), IColumnsDefinition::eType_string);
+		rColumns.AddColumn(_T("use_error_type"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("error_type"), IColumnsDefinition::eType_int);
+		rColumns.AddColumn(_T("use_system_error_no"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("system_error_no"), IColumnsDefinition::eType_ulong);
+		rColumns.AddColumn(_T("result"), IColumnsDefinition::eType_int);
+	}
+
+	void FeedbackErrorRule::Store(const ISerializerContainerPtr& spContainer) const
+	{
+		bool bAdded = m_setModifications[FeedbackErrorRuleEnum::eMod_Added];
+		if(m_setModifications.any())
+		{
+			ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, bAdded);
+
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_UseMask])
+				rRow.SetValue(_T("use_mask"), m_bUseMask);
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_Mask])
+				rRow.SetValue(_T("mask"), GetCombinedMask());
+
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_UseExcludeMask])
+				rRow.SetValue(_T("use_exclude_mask"), m_bUseExcludeMask);
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_ExcludeMask])
+				rRow.SetValue(_T("exclude_mask"), GetCombinedExcludeMask());
+
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_UseErrorType])
+				rRow.SetValue(_T("use_error_type"), m_bUseErrorType);
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_ErrorType])
+				rRow.SetValue(_T("error_type"), m_eErrorType);
+
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_UseSystemErrorNo])
+				rRow.SetValue(_T("use_system_error_no"), m_bUseSystemErrorNo);
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_SystemErrorNo])
+				rRow.SetValue(_T("system_error_no"), m_ulSystemErrorNo);
+
+			if(bAdded || m_setModifications[FeedbackErrorRuleEnum::eMod_Result])
+				rRow.SetValue(_T("result"), m_eResult);
+
+			m_setModifications.reset();
+		}
+	}
+
+	void FeedbackErrorRule::Load(const ISerializerRowReaderPtr& spRowReader)
+	{
+		TString strMask;
+
+		spRowReader->GetValue(_T("use_mask"), m_bUseMask.Modify());
+		spRowReader->GetValue(_T("mask"), strMask);
+		SetCombinedMask(strMask);
+
+		spRowReader->GetValue(_T("use_exclude_mask"), m_bUseExcludeMask.Modify());
+		spRowReader->GetValue(_T("exclude_mask"), strMask);
+		SetCombinedExcludeMask(strMask);
+
+		spRowReader->GetValue(_T("use_error_type"), m_bUseErrorType.Modify());
+		spRowReader->GetValue(_T("error_type"), *(int*)&m_eErrorType.Modify());
+
+		spRowReader->GetValue(_T("use_system_error_no"), m_bUseSystemErrorNo.Modify());
+		spRowReader->GetValue(_T("system_error_no"), m_ulSystemErrorNo.Modify());
+
+		spRowReader->GetValue(_T("result"), *(int*)&m_eResult.Modify());
+
+		m_setModifications.reset();
+	}
+
+	void FeedbackErrorRule::StoreInConfig(TConfig& rConfig) const
+	{
+		SetConfigValue(rConfig, _T("IncludeMask.Use"), m_bUseMask.Get());
+		SetConfigValue(rConfig, _T("IncludeMask.MaskList.Mask"), m_spaMask.Get().ToSerializedStringArray());
+
+		SetConfigValue(rConfig, _T("ExcludeMask.Use"), m_bUseExcludeMask.Get());
+		SetConfigValue(rConfig, _T("ExcludeMask.MaskList.Mask"), m_spaExcludeMask.Get().ToSerializedStringArray());
+
+		SetConfigValue(rConfig, _T("ErrorType.Use"), m_bUseErrorType.Get());
+		SetConfigValue(rConfig, _T("ErrorType.Value"), m_eErrorType.Get());
+
+		SetConfigValue(rConfig, _T("SystemErrorNo.Use"), m_bUseSystemErrorNo.Get());
+		SetConfigValue(rConfig, _T("SystemErrorNo.Value"), m_ulSystemErrorNo.Get());
+
+		SetConfigValue(rConfig, _T("Result"), m_eResult.Get());
+	}
+
+	void FeedbackErrorRule::ReadFromConfig(const TConfig& rConfig)
+	{
+		if(!GetConfigValue(rConfig, _T("IncludeMask.Use"), m_bUseMask.Modify()))
+			m_bUseMask = false;
+
+		TStringArray arrMask;
+		m_spaMask.Modify().Clear();
+		GetConfigValue(rConfig, _T("IncludeMask.MaskList.Mask"), arrMask);
+		m_spaMask.Modify().FromSerializedStringArray(arrMask);
+
+		if(!GetConfigValue(rConfig, _T("ExcludeMask.Use"), m_bUseExcludeMask.Modify()))
+			m_bUseExcludeMask = false;
+
+		m_spaExcludeMask.Modify().Clear();
+		GetConfigValue(rConfig, _T("ExcludeMask.MaskList.Mask"), arrMask);
+		m_spaExcludeMask.Modify().FromSerializedStringArray(arrMask);
+
+		if(!GetConfigValue(rConfig, _T("ErrorType.Use"), m_bUseErrorType.Modify()))
+			m_bUseErrorType = false;
+		if(!GetConfigValue(rConfig, _T("ErrorType.Value"), *(int*)m_eErrorType.Modify()))
+			m_eErrorType = EFileError::eDeleteError;
+
+		if(!GetConfigValue(rConfig, _T("SystemErrorNo.Use"), m_bUseSystemErrorNo.Modify()))
+			m_bUseSystemErrorNo = false;
+		if(!GetConfigValue(rConfig, _T("SystemErrorNo.Value"), m_ulSystemErrorNo.Modify()))
+			m_ulSystemErrorNo = 0UL;
+
+		if(!GetConfigValue(rConfig, _T("Result"), *(int*)m_eResult.Modify()))
+			m_eResult = eResult_Unknown;
+	}
+
+	bool FeedbackErrorRule::HaveSameCondition(const FeedbackErrorRule& rSrc) const
+	{
+		if(m_bUseMask != rSrc.m_bUseMask)
+			return false;
+		else if(m_bUseMask == true && m_spaMask != rSrc.m_spaMask)
+			return false;
+
+		if(m_bUseExcludeMask != rSrc.m_bUseExcludeMask)
+			return false;
+		else if(m_bUseExcludeMask == true && m_spaExcludeMask != rSrc.m_spaExcludeMask)
+			return false;
+
+		if(m_bUseErrorType != rSrc.m_bUseErrorType)
+			return false;
+		else if(m_bUseErrorType == true && m_eErrorType != rSrc.m_eErrorType)
+			return false;
+
+		if(m_bUseSystemErrorNo != rSrc.m_bUseSystemErrorNo)
+			return false;
+		else if(m_bUseSystemErrorNo == true && m_ulSystemErrorNo != rSrc.m_ulSystemErrorNo)
+			return false;
+
+		return true;
+	}
+
+	void FeedbackErrorRule::SetUseMask(bool bUseMask)
+	{
+		m_bUseMask = bUseMask;
+	}
+
+	bool FeedbackErrorRule::GetUseMask() const
+	{
+		return m_bUseMask;
+	}
+
+	bool FeedbackErrorRule::GetUseExcludeMask() const
+	{
+		return m_bUseExcludeMask;
+	}
+
+	void FeedbackErrorRule::SetUseExcludeMask(bool bUseExcludeMask)
+	{
+		m_bUseExcludeMask = bUseExcludeMask;
+	}
+
+	bool FeedbackErrorRule::GetUseErrorType() const
+	{
+		return m_bUseErrorType;
+	}
+
+	void FeedbackErrorRule::SetUseErrorType(bool bUseErrorType)
+	{
+		m_bUseErrorType = bUseErrorType;
+	}
+
+	EFileError FeedbackErrorRule::GetErrorType() const
+	{
+		return m_eErrorType;
+	}
+
+	void FeedbackErrorRule::SetErrorType(EFileError eErrorType)
+	{
+		m_eErrorType = eErrorType;
+	}
+
+	bool FeedbackErrorRule::GetUseSystemErrorNo() const
+	{
+		return m_bUseSystemErrorNo;
+	}
+
+	void FeedbackErrorRule::SetUseSystemErrorNo(bool bUseSystemErrorNo)
+	{
+		m_bUseSystemErrorNo = bUseSystemErrorNo;
+	}
+
+	unsigned int FeedbackErrorRule::GetSystemErrorNo() const
+	{
+		return m_ulSystemErrorNo;
+	}
+
+	void FeedbackErrorRule::SetSystemErrorNo(unsigned int ulErrorNo)
+	{
+		m_ulSystemErrorNo = ulErrorNo;
+	}
+
+	TString FeedbackErrorRule::GetCombinedMask() const
+	{
+		return m_spaMask.Get().ToString();
+	}
+
+	void FeedbackErrorRule::SetCombinedMask(const TString& strMask)
+	{
+		TStringPatternArray& rPatterns = m_spaMask.Modify();
+		rPatterns.Clear();
+		rPatterns.FromString(strMask);
+	}
+
+	TString FeedbackErrorRule::GetCombinedExcludeMask() const
+	{
+		return m_spaExcludeMask.Get().ToString();
+	}
+
+	void FeedbackErrorRule::SetCombinedExcludeMask(const TString& strMask)
+	{
+		TStringPatternArray& rPatterns = m_spaExcludeMask.Modify();
+		rPatterns.Clear();
+		rPatterns.FromString(strMask);
+	}
+
+	chengine::EFeedbackResult FeedbackErrorRule::GetResult() const
+	{
+		return m_eResult;
+	}
+
+	void FeedbackErrorRule::SetResult(EFeedbackResult eResult)
+	{
+		m_eResult = eResult;
+	}
+}
Index: src/libchengine/FeedbackErrorRule.h
===================================================================
diff -u
--- src/libchengine/FeedbackErrorRule.h	(revision 0)
+++ src/libchengine/FeedbackErrorRule.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,103 @@
+#pragma once
+
+#include "libchengine.h"
+#include "../libserializer/SerializableObject.h"
+#include "../libstring/TStringPatternArray.h"
+#include "ECompareType.h"
+#include "EFeedbackResult.h"
+#include "../libserializer/SerializerDataTypes.h"
+#include <bitset>
+#include "../libserializer/TSharedModificationTracker.h"
+#include "TFileInfo.h"
+#include "TConfig.h"
+#include "EFileError.h"
+
+namespace chengine
+{
+	namespace FeedbackErrorRuleEnum
+	{
+		enum EModifications
+		{
+			eMod_Added,
+			eMod_UseMask,
+			eMod_Mask,
+			eMod_UseExcludeMask,
+			eMod_ExcludeMask,
+			eMod_UseErrorType,
+			eMod_ErrorType,
+			eMod_UseSystemErrorNo,
+			eMod_SystemErrorNo,
+			eMod_Result,
+
+			eMod_Last
+		};
+	}
+
+#pragma warning(push)
+#pragma warning(disable: 4251)
+	class LIBCHENGINE_API FeedbackErrorRule : public serializer::SerializableObject<FeedbackErrorRuleEnum::eMod_Last>
+	{
+	public:
+		FeedbackErrorRule();
+		FeedbackErrorRule(const FeedbackErrorRule& rSrc);
+		FeedbackErrorRule& operator=(const FeedbackErrorRule& rSrc);
+
+		bool operator==(const FeedbackErrorRule& rSrc) const;
+		bool operator!=(const FeedbackErrorRule& rSrc) const;
+
+		void SetData(const FeedbackErrorRule& rSrc);
+
+		bool Matches(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eErrorType, unsigned long ulError, EFeedbackResult& eResult) const;
+
+		void Store(const serializer::ISerializerContainerPtr& spContainer) const override;
+		void Load(const serializer::ISerializerRowReaderPtr& spRowReader) override;
+		static void InitColumns(serializer::IColumnsDefinition& rColumns);
+
+		void StoreInConfig(TConfig& rConfig) const;
+		void ReadFromConfig(const TConfig& rConfig);
+
+		// comparison
+		bool HaveSameCondition(const FeedbackErrorRule& rSrc) const;
+
+		// get/set
+		// atrributes access
+		bool GetUseMask() const;
+		void SetUseMask(bool bUseMask);
+
+		string::TString GetCombinedMask() const;
+		void SetCombinedMask(const string::TString& strMask);
+
+		bool GetUseExcludeMask() const;
+		void SetUseExcludeMask(bool bUseExcludeMask);
+
+		string::TString GetCombinedExcludeMask() const;
+		void SetCombinedExcludeMask(const string::TString& strMask);
+
+		bool GetUseErrorType() const;
+		void SetUseErrorType(bool bUseErrorType);
+		EFileError GetErrorType() const;
+		void SetErrorType(EFileError eErrorType);
+
+		bool GetUseSystemErrorNo() const;
+		void SetUseSystemErrorNo(bool bUseSystemErrorNo);
+		unsigned int GetSystemErrorNo() const;
+		void SetSystemErrorNo(unsigned int ulErrorNo);
+
+		EFeedbackResult GetResult() const;
+		void SetResult(EFeedbackResult eResult);
+
+	private:
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackErrorRuleEnum::eMod_UseMask> m_bUseMask;
+		serializer::TSharedModificationTracker<string::TStringPatternArray, Bitset, FeedbackErrorRuleEnum::eMod_Mask> m_spaMask;
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackErrorRuleEnum::eMod_UseExcludeMask> m_bUseExcludeMask;
+		serializer::TSharedModificationTracker<string::TStringPatternArray, Bitset, FeedbackErrorRuleEnum::eMod_ExcludeMask> m_spaExcludeMask;
+
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackErrorRuleEnum::eMod_UseErrorType> m_bUseErrorType;
+		serializer::TSharedModificationTracker<EFileError, Bitset, FeedbackErrorRuleEnum::eMod_ErrorType> m_eErrorType;
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackErrorRuleEnum::eMod_UseSystemErrorNo> m_bUseSystemErrorNo;
+		serializer::TSharedModificationTracker<unsigned int, Bitset, FeedbackErrorRuleEnum::eMod_SystemErrorNo> m_ulSystemErrorNo;
+
+		serializer::TSharedModificationTracker<EFeedbackResult, Bitset, FeedbackErrorRuleEnum::eMod_Result> m_eResult;
+	};
+#pragma warning(pop)
+}
Index: src/libchengine/FeedbackErrorRuleList.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackErrorRuleList.cpp	(revision 0)
+++ src/libchengine/FeedbackErrorRuleList.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,90 @@
+#include "stdafx.h"
+#include "FeedbackErrorRuleList.h"
+#include "TConfigArray.h"
+#include "../libserializer/IColumnsDefinition.h"
+#include "TFileFilter.h"
+
+using namespace string;
+using namespace serializer;
+
+namespace chengine
+{
+	EFeedbackResult FeedbackErrorRuleList::Matches(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eErrorType, unsigned long ulError) const
+	{
+		if(m_vEntries.empty())
+			return eResult_Unknown;
+
+		for(const FeedbackErrorRule& rRule : m_vEntries)
+		{
+			EFeedbackResult eResult = eResult_Unknown;
+			if(rRule.Matches(strSrcPath, strDstPath, eErrorType, ulError, eResult))
+				return eResult;
+		}
+
+		return eResult_Unknown;
+	}
+
+	void FeedbackErrorRuleList::Merge(const FeedbackErrorRuleList& rSrc)
+	{
+		for(size_t stIndex = 0; stIndex < rSrc.GetCount(); ++stIndex)
+		{
+			InsertOrUpdateRule(rSrc.GetAt(stIndex));
+		}
+	}
+
+	void FeedbackErrorRuleList::InsertOrUpdateRule(const FeedbackErrorRule& rRule)
+	{
+		bool bFound = false;
+		for(size_t stIndex = 0; stIndex < GetCount(); ++stIndex)
+		{
+			FeedbackErrorRule& rCurrent = GetAt(stIndex);
+			if(rCurrent.HaveSameCondition(rRule))
+			{
+				bFound = true;
+				rCurrent.SetResult(rRule.GetResult());
+			}
+		}
+
+		if(!bFound)
+			InsertAt(0, rRule);
+	}
+
+	void FeedbackErrorRuleList::InitColumns(const serializer::ISerializerContainerPtr& spContainer) const
+	{
+		IColumnsDefinition& rColumns = spContainer->GetColumnsDefinition();
+		if(rColumns.IsEmpty())
+			TFileFilter::InitColumns(rColumns);
+	}
+
+	void FeedbackErrorRuleList::StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const
+	{
+		rConfig.DeleteNode(pszNodeName);
+		for(const FeedbackErrorRule& rRule : m_vEntries)
+		{
+			TConfig cfgNode;
+			rRule.StoreInConfig(cfgNode);
+
+			TString strNode = TString(pszNodeName) + _T(".RuleDefinition");
+			rConfig.AddSubConfig(strNode.c_str(), cfgNode);
+		}
+	}
+
+	bool FeedbackErrorRuleList::ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName)
+	{
+		m_vEntries.clear();
+
+		TConfigArray vConfigs;
+		if(!rConfig.ExtractMultiSubConfigs(pszNodeName, vConfigs))
+			return false;
+
+		for(size_t stIndex = 0; stIndex < vConfigs.GetCount(); ++stIndex)
+		{
+			const TConfig& rCfg = vConfigs.GetAt(stIndex);
+			FeedbackErrorRule rule;
+			rule.ReadFromConfig(rCfg);
+
+			m_vEntries.push_back(rule);
+		}
+		return true;
+	}
+}
Index: src/libchengine/FeedbackErrorRuleList.h
===================================================================
diff -u
--- src/libchengine/FeedbackErrorRuleList.h	(revision 0)
+++ src/libchengine/FeedbackErrorRuleList.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "libchengine.h"
+#include "FeedbackErrorRule.h"
+#include "TConfig.h"
+#include "../libserializer/SerializableContainer.h"
+
+namespace chengine
+{
+#pragma warning(push)
+#pragma warning(disable: 4251)
+
+	class LIBCHENGINE_API FeedbackErrorRuleList : public serializer::SerializableContainer<FeedbackErrorRule>
+	{
+	public:
+		EFeedbackResult Matches(const string::TString& strSrcPath, const string::TString& /*strDstPath*/, EFileError eErrorType, unsigned long ulError) const;
+
+		void Merge(const FeedbackErrorRuleList& rSrc);
+
+		void InitColumns(const serializer::ISerializerContainerPtr& spContainer) const override;
+
+		void StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const;
+		bool ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName);
+
+	private:
+		void InsertOrUpdateRule(const FeedbackErrorRule& rRule);
+	};
+#pragma warning(pop)
+}
+
+CONFIG_MEMBER_SERIALIZATION(FeedbackErrorRuleList)
Index: src/libchengine/FeedbackManager.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackManager.cpp	(revision 0)
+++ src/libchengine/FeedbackManager.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,226 @@
+// ============================================================================
+//  Copyright (C) 2001-2015 by Jozef Starosczyk
+//  ixen@copyhandler.com
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Library General Public License
+//  (version 2) as published by the Free Software Foundation;
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU Library General Public
+//  License along with this program; if not, write to the
+//  Free Software Foundation, Inc.,
+//  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+// ============================================================================
+#include "stdafx.h"
+#include "FeedbackManager.h"
+#include <boost/thread/locks.hpp>
+#include "../libserializer/ISerializerRowData.h"
+#include "TScopedRunningTimeTrackerPause.h"
+#include "../libchcore/TCoreException.h"
+#include "../libchcore/ErrorCodes.h"
+
+using namespace serializer;
+using namespace chcore;
+
+namespace chengine
+{
+	FeedbackManager::FeedbackManager(const IFeedbackHandlerPtr& spFeedbackHandler) :
+		m_spFeedbackHandler(spFeedbackHandler)
+	{
+		if(!spFeedbackHandler)
+			throw TCoreException(eErr_InvalidArgument, L"spFeedbackHandler", LOCATION);
+	}
+
+	void FeedbackManager::SetRules(const FeedbackRules& rRules)
+	{
+		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+		m_feedbackRules = rRules;
+	}
+
+	chengine::FeedbackRules FeedbackManager::GetRules() const
+	{
+		boost::shared_lock<boost::shared_mutex> lock(m_lock);
+		chengine::FeedbackRules rules = m_feedbackRules;
+		return rules;
+	}
+
+	chengine::TFeedbackResult FeedbackManager::FileError(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eFileError, unsigned long ulError)
+	{
+		bool bAutomatedResponse = true;
+
+		EFeedbackResult eResult = eResult_Unknown;
+
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			eResult = m_feedbackRules.GetErrorRules().Matches(strSrcPath, strDstPath, eFileError, ulError);
+		}
+
+		if(eResult == eResult_Unknown)
+		{
+			FeedbackErrorRuleList newRules;
+			{
+				TScopedRunningTimeTrackerPause scopedTimePause(m_pTimeTracker);
+				TScopedRunningTimeTrackerPause scopedSecondaryTimePause(m_pSecondaryTimeTracker);
+				eResult = m_spFeedbackHandler->FileError(strSrcPath, strDstPath, eFileError, ulError, newRules);
+			}
+			if(eResult != eResult_Unknown)
+			{
+				bAutomatedResponse = false;
+				if(!newRules.IsEmpty())
+				{
+					boost::unique_lock<boost::shared_mutex> lock(m_lock);
+					m_feedbackRules.GetErrorRules().Merge(newRules);
+				}
+			}
+		}
+
+		return { eResult, bAutomatedResponse };
+	}
+
+	chengine::TFeedbackResult FeedbackManager::FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo)
+	{
+		bool bAutomatedResponse = true;
+		EFeedbackResult eResult = eResult_Unknown;
+
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			eResult = m_feedbackRules.GetAlreadyExistsRules().Matches(spSrcFileInfo, spDstFileInfo);
+		}
+		if(eResult == eResult_Unknown)
+		{
+			FeedbackAlreadyExistsRuleList newRules;
+			{
+				TScopedRunningTimeTrackerPause scopedTimePause(m_pTimeTracker);
+				TScopedRunningTimeTrackerPause scopedSecondaryTimePause(m_pSecondaryTimeTracker);
+				eResult = m_spFeedbackHandler->FileAlreadyExists(spSrcFileInfo, spDstFileInfo, newRules);
+			}
+			if(eResult != eResult_Unknown)
+			{
+				bAutomatedResponse = false;
+				if(!newRules.IsEmpty())
+				{
+					boost::unique_lock<boost::shared_mutex> lock(m_lock);
+					m_feedbackRules.GetAlreadyExistsRules().Merge(newRules);
+				}
+			}
+		}
+
+		return { eResult, bAutomatedResponse };
+	}
+
+	chengine::TFeedbackResult FeedbackManager::NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize)
+	{
+		bool bAutomatedResponse = true;
+		EFeedbackResult eResult = eResult_Unknown;
+
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			eResult = m_feedbackRules.GetNotEnoughSpaceRules().Matches(strSrcPath, strDstPath, ullRequiredSize);
+		}
+		if(eResult == eResult_Unknown)
+		{
+			FeedbackNotEnoughSpaceRuleList newRules;
+			{
+				TScopedRunningTimeTrackerPause scopedTimePause(m_pTimeTracker);
+				TScopedRunningTimeTrackerPause scopedSecondaryTimePause(m_pSecondaryTimeTracker);
+				eResult = m_spFeedbackHandler->NotEnoughSpace(strSrcPath, strDstPath, ullRequiredSize, newRules);
+			}
+			if(eResult != eResult_Unknown)
+			{
+				bAutomatedResponse = false;
+				if(!newRules.IsEmpty())
+				{
+					boost::unique_lock<boost::shared_mutex> lock(m_lock);
+					m_feedbackRules.GetNotEnoughSpaceRules().Merge(newRules);
+				}
+			}
+		}
+
+		return { eResult, bAutomatedResponse };
+	}
+
+	chengine::TFeedbackResult FeedbackManager::OperationEvent(EOperationEvent eEvent)
+	{
+		bool bAutomatedResponse = true;
+		EFeedbackResult eResult = eResult_Unknown;
+
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			eResult = m_feedbackRules.GetOperationEventRules().Matches(eEvent);
+		}
+		if(eResult == eResult_Unknown)
+		{
+			FeedbackOperationEventRuleList newRules;
+			{
+				TScopedRunningTimeTrackerPause scopedTimePause(m_pTimeTracker);
+				TScopedRunningTimeTrackerPause scopedSecondaryTimePause(m_pSecondaryTimeTracker);
+				eResult = m_spFeedbackHandler->OperationEvent(eEvent, newRules);
+			}
+			if(eResult != eResult_Unknown)
+			{
+				bAutomatedResponse = false;
+				if(!newRules.IsEmpty())
+				{
+					boost::unique_lock<boost::shared_mutex> lock(m_lock);
+					m_feedbackRules.GetOperationEventRules().Merge(newRules);
+				}
+			}
+		}
+
+		return { eResult, bAutomatedResponse };
+	}
+
+	void FeedbackManager::Store(const ISerializerPtr& spSerializer) const
+	{
+		boost::shared_lock<boost::shared_mutex> lock(m_lock);
+
+		ISerializerContainerPtr spContainer = spSerializer->GetContainer(L"feedback_error");
+		m_feedbackRules.GetErrorRules().Store(spContainer);
+
+		spContainer = spSerializer->GetContainer(L"feedback_already_exists");
+		m_feedbackRules.GetAlreadyExistsRules().Store(spContainer);
+
+		spContainer = spSerializer->GetContainer(L"feedback_not_enough_space");
+		m_feedbackRules.GetNotEnoughSpaceRules().Store(spContainer);
+
+		spContainer = spSerializer->GetContainer(L"feedback_operation_event");
+		m_feedbackRules.GetOperationEventRules().Store(spContainer);
+	}
+
+	void FeedbackManager::Load(const ISerializerPtr& spSerializer)
+	{
+		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+		ISerializerContainerPtr spContainer = spSerializer->GetContainer(L"feedback_error");
+		m_feedbackRules.GetErrorRules().Load(spContainer);
+
+		spContainer = spSerializer->GetContainer(L"feedback_already_exists");
+		m_feedbackRules.GetAlreadyExistsRules().Load(spContainer);
+
+		spContainer = spSerializer->GetContainer(L"feedback_not_enough_space");
+		m_feedbackRules.GetNotEnoughSpaceRules().Load(spContainer);
+
+		spContainer = spSerializer->GetContainer(L"feedback_operation_event");
+		m_feedbackRules.GetOperationEventRules().Load(spContainer);
+	}
+
+	DWORD FeedbackManager::GetRetryInterval() const
+	{
+		return 100;
+	}
+
+	void FeedbackManager::RestoreDefaults()
+	{
+		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+		m_feedbackRules.GetErrorRules().Clear();
+		m_feedbackRules.GetAlreadyExistsRules().Clear();
+		m_feedbackRules.GetNotEnoughSpaceRules().Clear();
+		m_feedbackRules.GetOperationEventRules().Clear();
+	}
+}
Index: src/libchengine/FeedbackManager.h
===================================================================
diff -u
--- src/libchengine/FeedbackManager.h	(revision 0)
+++ src/libchengine/FeedbackManager.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,75 @@
+// ============================================================================
+//  Copyright (C) 2001-2015 by Jozef Starosczyk
+//  ixen@copyhandler.com
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Library General Public License
+//  (version 2) as published by the Free Software Foundation;
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU Library General Public
+//  License along with this program; if not, write to the
+//  Free Software Foundation, Inc.,
+//  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+// ============================================================================
+#ifndef __TFEEDBACKHANDLERBASE_H__
+#define __TFEEDBACKHANDLERBASE_H__
+
+#include "IFeedbackHandler.h"
+#include <bitset>
+#include "../libserializer/TSharedModificationTracker.h"
+#include "../libserializer/ISerializer.h"
+#include "TScopedRunningTimeTracker.h"
+#include "FeedbackRules.h"
+
+namespace chengine
+{
+	class LIBCHENGINE_API FeedbackManager
+	{
+	public:
+		FeedbackManager(const IFeedbackHandlerPtr& spFeedbackHandler);
+		FeedbackManager(const FeedbackManager&) = delete;
+
+		FeedbackManager& operator=(const FeedbackManager&) = delete;
+
+		void SetRules(const FeedbackRules& rRules);
+		FeedbackRules GetRules() const;
+
+		TFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eFileError, unsigned long ulError);
+		TFeedbackResult FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo);
+		TFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize);
+		TFeedbackResult OperationEvent(EOperationEvent eEvent);
+
+		// resets the permanent status from all responses
+		void RestoreDefaults();
+
+		void SetTimeTracker(TScopedRunningTimeTracker* pTimeTracker) { m_pTimeTracker = pTimeTracker; }
+		void SetSecondaryTimeTracker(TScopedRunningTimeTracker* pTimeTracker) { m_pSecondaryTimeTracker = pTimeTracker; }
+
+		// serialization
+		void Store(const serializer::ISerializerPtr& spSerializer) const;
+		void Load(const serializer::ISerializerPtr& spSerializer);
+
+		DWORD GetRetryInterval() const;
+
+	private:
+#pragma warning(push)
+#pragma warning(disable: 4251)
+		mutable boost::shared_mutex m_lock;
+
+		IFeedbackHandlerPtr m_spFeedbackHandler;
+		TScopedRunningTimeTracker* m_pTimeTracker = nullptr;
+		TScopedRunningTimeTracker* m_pSecondaryTimeTracker = nullptr;
+#pragma warning(pop)
+
+		FeedbackRules m_feedbackRules;
+	};
+
+	using FeedbackManagerPtr = std::shared_ptr<FeedbackManager>;
+}
+
+#endif
Index: src/libchengine/FeedbackNotEnoughSpaceRule.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackNotEnoughSpaceRule.cpp	(revision 0)
+++ src/libchengine/FeedbackNotEnoughSpaceRule.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,253 @@
+#include "stdafx.h"
+#include "FeedbackNotEnoughSpaceRule.h"
+#include "../libstring/TString.h"
+#include "../libstring/TStringArray.h"
+#include "../libchcore/TPath.h"
+
+using namespace serializer;
+using namespace string;
+using namespace chcore;
+
+namespace chengine
+{
+	FeedbackNotEnoughSpaceRule::FeedbackNotEnoughSpaceRule() :
+		m_bUseMask(m_setModifications, false),
+		m_spaMask(m_setModifications),
+		m_bUseExcludeMask(m_setModifications, false),
+		m_spaExcludeMask(m_setModifications),
+		m_eResult(m_setModifications, eResult_Unknown)
+	{
+		m_setModifications[FeedbackNotEnoughSpaceRuleEnum::eMod_Added] = true;
+	}
+
+
+	FeedbackNotEnoughSpaceRule::FeedbackNotEnoughSpaceRule(const FeedbackNotEnoughSpaceRule& rSrc) :
+		serializer::SerializableObject<FeedbackNotEnoughSpaceRuleEnum::eMod_Last>(rSrc),
+		m_bUseMask(rSrc.m_bUseMask, m_setModifications),
+		m_spaMask(rSrc.m_spaMask, m_setModifications),
+		m_bUseExcludeMask(rSrc.m_bUseExcludeMask, m_setModifications),
+		m_spaExcludeMask(rSrc.m_spaExcludeMask, m_setModifications),
+		m_eResult(rSrc.m_eResult, m_setModifications)
+	{
+	}
+
+	FeedbackNotEnoughSpaceRule& FeedbackNotEnoughSpaceRule::operator=(const FeedbackNotEnoughSpaceRule& rSrc)
+	{
+		if(this == &rSrc)
+			return *this;
+
+		__super::operator=(rSrc);
+
+		SetData(rSrc);
+
+		return *this;
+	}
+
+	bool FeedbackNotEnoughSpaceRule::operator==(const FeedbackNotEnoughSpaceRule& rSrc) const
+	{
+		if(m_bUseMask != rSrc.m_bUseMask)
+			return false;
+		if(m_spaMask != rSrc.m_spaMask)
+			return false;
+
+		if(m_bUseExcludeMask != rSrc.m_bUseExcludeMask)
+			return false;
+
+		if(m_spaExcludeMask != rSrc.m_spaExcludeMask)
+			return false;
+
+		if(m_eResult != rSrc.m_eResult)
+			return false;
+
+		return true;
+	}
+
+	bool FeedbackNotEnoughSpaceRule::operator!=(const FeedbackNotEnoughSpaceRule& rSrc) const
+	{
+		return !operator==(rSrc);
+	}
+
+	void FeedbackNotEnoughSpaceRule::SetData(const FeedbackNotEnoughSpaceRule& rSrc)
+	{
+		if(this == &rSrc)
+			return;
+
+		m_bUseMask = rSrc.m_bUseMask;
+		m_spaMask = rSrc.m_spaMask;
+		m_bUseExcludeMask = rSrc.m_bUseExcludeMask;
+		m_spaExcludeMask = rSrc.m_spaExcludeMask;
+		m_eResult = rSrc.m_eResult;
+	}
+
+	bool FeedbackNotEnoughSpaceRule::Matches(const string::TString& /*strSrcPath*/, const string::TString& strDstPath, unsigned long long /*ullRequiredSize*/, EFeedbackResult& eResult) const
+	{
+		eResult = eResult_Unknown;
+
+		TSmartPath path = PathFromWString(strDstPath);
+		if(m_bUseMask)
+		{
+			if(!m_spaMask.Get().MatchesAny(path.GetFileName().ToString()))
+				return false;
+		}
+		if(m_bUseExcludeMask)
+		{
+			if(m_spaExcludeMask.Get().MatchesAny(path.GetFileName().ToString()))
+				return false;
+		}
+
+		eResult = m_eResult;
+		return true;
+	}
+
+	void FeedbackNotEnoughSpaceRule::InitColumns(serializer::IColumnsDefinition& rColumns)
+	{
+		rColumns.AddColumn(_T("id"), ColumnType<object_id_t>::value);
+		rColumns.AddColumn(_T("use_mask"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("mask"), IColumnsDefinition::eType_string);
+		rColumns.AddColumn(_T("use_exclude_mask"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("exclude_mask"), IColumnsDefinition::eType_string);
+		rColumns.AddColumn(_T("result"), IColumnsDefinition::eType_int);
+	}
+
+	void FeedbackNotEnoughSpaceRule::Store(const ISerializerContainerPtr& spContainer) const
+	{
+		bool bAdded = m_setModifications[FeedbackNotEnoughSpaceRuleEnum::eMod_Added];
+		if(m_setModifications.any())
+		{
+			ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, bAdded);
+
+			if(bAdded || m_setModifications[FeedbackNotEnoughSpaceRuleEnum::eMod_UseMask])
+				rRow.SetValue(_T("use_mask"), m_bUseMask);
+			if(bAdded || m_setModifications[FeedbackNotEnoughSpaceRuleEnum::eMod_Mask])
+				rRow.SetValue(_T("mask"), GetCombinedMask());
+
+			if(bAdded || m_setModifications[FeedbackNotEnoughSpaceRuleEnum::eMod_UseExcludeMask])
+				rRow.SetValue(_T("use_exclude_mask"), m_bUseExcludeMask);
+			if(bAdded || m_setModifications[FeedbackNotEnoughSpaceRuleEnum::eMod_ExcludeMask])
+				rRow.SetValue(_T("exclude_mask"), GetCombinedExcludeMask());
+
+			if(bAdded || m_setModifications[FeedbackNotEnoughSpaceRuleEnum::eMod_Result])
+				rRow.SetValue(_T("result"), m_eResult);
+
+			m_setModifications.reset();
+		}
+	}
+
+	void FeedbackNotEnoughSpaceRule::Load(const ISerializerRowReaderPtr& spRowReader)
+	{
+		TString strMask;
+
+		spRowReader->GetValue(_T("use_mask"), m_bUseMask.Modify());
+		spRowReader->GetValue(_T("mask"), strMask);
+		SetCombinedMask(strMask);
+
+		spRowReader->GetValue(_T("use_exclude_mask"), m_bUseExcludeMask.Modify());
+		spRowReader->GetValue(_T("exclude_mask"), strMask);
+		SetCombinedExcludeMask(strMask);
+
+		spRowReader->GetValue(_T("result"), *(int*)&m_eResult.Modify());
+
+		m_setModifications.reset();
+	}
+
+	void FeedbackNotEnoughSpaceRule::StoreInConfig(TConfig& rConfig) const
+	{
+		SetConfigValue(rConfig, _T("IncludeMask.Use"), m_bUseMask.Get());
+		SetConfigValue(rConfig, _T("IncludeMask.MaskList.Mask"), m_spaMask.Get().ToSerializedStringArray());
+
+		SetConfigValue(rConfig, _T("ExcludeMask.Use"), m_bUseExcludeMask.Get());
+		SetConfigValue(rConfig, _T("ExcludeMask.MaskList.Mask"), m_spaExcludeMask.Get().ToSerializedStringArray());
+
+		SetConfigValue(rConfig, _T("Result"), m_eResult.Get());
+	}
+
+	void FeedbackNotEnoughSpaceRule::ReadFromConfig(const TConfig& rConfig)
+	{
+		if(!GetConfigValue(rConfig, _T("IncludeMask.Use"), m_bUseMask.Modify()))
+			m_bUseMask = false;
+
+		TStringArray arrMask;
+		m_spaMask.Modify().Clear();
+		GetConfigValue(rConfig, _T("IncludeMask.MaskList.Mask"), arrMask);
+		m_spaMask.Modify().FromSerializedStringArray(arrMask);
+
+		if(!GetConfigValue(rConfig, _T("ExcludeMask.Use"), m_bUseExcludeMask.Modify()))
+			m_bUseExcludeMask = false;
+
+		m_spaExcludeMask.Modify().Clear();
+		GetConfigValue(rConfig, _T("ExcludeMask.MaskList.Mask"), arrMask);
+		m_spaExcludeMask.Modify().FromSerializedStringArray(arrMask);
+
+		if(!GetConfigValue(rConfig, _T("Result"), *(int*)m_eResult.Modify()))
+			m_eResult = eResult_Unknown;
+	}
+
+	bool FeedbackNotEnoughSpaceRule::HaveSameCondition(const FeedbackNotEnoughSpaceRule& rSrc) const
+	{
+		if(m_bUseMask != rSrc.m_bUseMask)
+			return false;
+		else if(m_bUseMask == true && m_spaMask != rSrc.m_spaMask)
+			return false;
+
+		if(m_bUseExcludeMask != rSrc.m_bUseExcludeMask)
+			return false;
+		else if(m_bUseExcludeMask == true && m_spaExcludeMask != rSrc.m_spaExcludeMask)
+			return false;
+
+		return true;
+	}
+
+	void FeedbackNotEnoughSpaceRule::SetUseMask(bool bUseMask)
+	{
+		m_bUseMask = bUseMask;
+	}
+
+	bool FeedbackNotEnoughSpaceRule::GetUseMask() const
+	{
+		return m_bUseMask;
+	}
+
+	bool FeedbackNotEnoughSpaceRule::GetUseExcludeMask() const
+	{
+		return m_bUseExcludeMask;
+	}
+
+	void FeedbackNotEnoughSpaceRule::SetUseExcludeMask(bool bUseExcludeMask)
+	{
+		m_bUseExcludeMask = bUseExcludeMask;
+	}
+
+	TString FeedbackNotEnoughSpaceRule::GetCombinedMask() const
+	{
+		return m_spaMask.Get().ToString();
+	}
+
+	void FeedbackNotEnoughSpaceRule::SetCombinedMask(const TString& strMask)
+	{
+		TStringPatternArray& rPatterns = m_spaMask.Modify();
+		rPatterns.Clear();
+		rPatterns.FromString(strMask);
+	}
+
+	TString FeedbackNotEnoughSpaceRule::GetCombinedExcludeMask() const
+	{
+		return m_spaExcludeMask.Get().ToString();
+	}
+
+	void FeedbackNotEnoughSpaceRule::SetCombinedExcludeMask(const TString& strMask)
+	{
+		TStringPatternArray& rPatterns = m_spaExcludeMask.Modify();
+		rPatterns.Clear();
+		rPatterns.FromString(strMask);
+	}
+
+	chengine::EFeedbackResult FeedbackNotEnoughSpaceRule::GetResult() const
+	{
+		return m_eResult;
+	}
+
+	void FeedbackNotEnoughSpaceRule::SetResult(EFeedbackResult eResult)
+	{
+		m_eResult = eResult;
+	}
+}
Index: src/libchengine/FeedbackNotEnoughSpaceRule.h
===================================================================
diff -u
--- src/libchengine/FeedbackNotEnoughSpaceRule.h	(revision 0)
+++ src/libchengine/FeedbackNotEnoughSpaceRule.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "libchengine.h"
+#include "../libserializer/SerializableObject.h"
+#include "../libstring/TStringPatternArray.h"
+#include "ECompareType.h"
+#include "EFeedbackResult.h"
+#include "../libserializer/SerializerDataTypes.h"
+#include <bitset>
+#include "../libserializer/TSharedModificationTracker.h"
+#include "TFileInfo.h"
+#include "TConfig.h"
+#include "EFileError.h"
+
+namespace chengine
+{
+	namespace FeedbackNotEnoughSpaceRuleEnum
+	{
+		enum EModifications
+		{
+			eMod_Added,
+			eMod_UseMask,
+			eMod_Mask,
+			eMod_UseExcludeMask,
+			eMod_ExcludeMask,
+			eMod_UseErrorType,
+			eMod_ErrorType,
+			eMod_UseSystemErrorNo,
+			eMod_SystemErrorNo,
+			eMod_Result,
+
+			eMod_Last
+		};
+	}
+
+#pragma warning(push)
+#pragma warning(disable: 4251)
+	class LIBCHENGINE_API FeedbackNotEnoughSpaceRule : public serializer::SerializableObject<FeedbackNotEnoughSpaceRuleEnum::eMod_Last>
+	{
+	public:
+		FeedbackNotEnoughSpaceRule();
+		FeedbackNotEnoughSpaceRule(const FeedbackNotEnoughSpaceRule& rSrc);
+		FeedbackNotEnoughSpaceRule& operator=(const FeedbackNotEnoughSpaceRule& rSrc);
+
+		bool operator==(const FeedbackNotEnoughSpaceRule& rSrc) const;
+		bool operator!=(const FeedbackNotEnoughSpaceRule& rSrc) const;
+
+		void SetData(const FeedbackNotEnoughSpaceRule& rSrc);
+
+		bool Matches(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize, EFeedbackResult& eResult) const;
+
+		void Store(const serializer::ISerializerContainerPtr& spContainer) const override;
+		void Load(const serializer::ISerializerRowReaderPtr& spRowReader) override;
+		static void InitColumns(serializer::IColumnsDefinition& rColumns);
+
+		void StoreInConfig(TConfig& rConfig) const;
+		void ReadFromConfig(const TConfig& rConfig);
+
+		// comparison
+		bool HaveSameCondition(const FeedbackNotEnoughSpaceRule& rSrc) const;
+
+		// get/set
+		// atrributes access
+		bool GetUseMask() const;
+		void SetUseMask(bool bUseMask);
+
+		string::TString GetCombinedMask() const;
+		void SetCombinedMask(const string::TString& strMask);
+
+		bool GetUseExcludeMask() const;
+		void SetUseExcludeMask(bool bUseExcludeMask);
+
+		string::TString GetCombinedExcludeMask() const;
+		void SetCombinedExcludeMask(const string::TString& strMask);
+
+		EFeedbackResult GetResult() const;
+		void SetResult(EFeedbackResult eResult);
+
+	private:
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackNotEnoughSpaceRuleEnum::eMod_UseMask> m_bUseMask;
+		serializer::TSharedModificationTracker<string::TStringPatternArray, Bitset, FeedbackNotEnoughSpaceRuleEnum::eMod_Mask> m_spaMask;
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackNotEnoughSpaceRuleEnum::eMod_UseExcludeMask> m_bUseExcludeMask;
+		serializer::TSharedModificationTracker<string::TStringPatternArray, Bitset, FeedbackNotEnoughSpaceRuleEnum::eMod_ExcludeMask> m_spaExcludeMask;
+
+		serializer::TSharedModificationTracker<EFeedbackResult, Bitset, FeedbackNotEnoughSpaceRuleEnum::eMod_Result> m_eResult;
+	};
+#pragma warning(pop)
+}
Index: src/libchengine/FeedbackNotEnoughSpaceRuleList.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackNotEnoughSpaceRuleList.cpp	(revision 0)
+++ src/libchengine/FeedbackNotEnoughSpaceRuleList.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,90 @@
+#include "stdafx.h"
+#include "FeedbackNotEnoughSpaceRuleList.h"
+#include "TConfigArray.h"
+#include "../libserializer/IColumnsDefinition.h"
+#include "TFileFilter.h"
+
+using namespace string;
+using namespace serializer;
+
+namespace chengine
+{
+	EFeedbackResult FeedbackNotEnoughSpaceRuleList::Matches(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize) const
+	{
+		if(m_vEntries.empty())
+			return eResult_Unknown;
+
+		for(const FeedbackNotEnoughSpaceRule& rRule : m_vEntries)
+		{
+			EFeedbackResult eResult = eResult_Unknown;
+			if(rRule.Matches(strSrcPath, strDstPath, ullRequiredSize, eResult))
+				return eResult;
+		}
+
+		return eResult_Unknown;
+	}
+
+	void FeedbackNotEnoughSpaceRuleList::Merge(const FeedbackNotEnoughSpaceRuleList& rSrc)
+	{
+		for(size_t stIndex = 0; stIndex < rSrc.GetCount(); ++stIndex)
+		{
+			InsertOrUpdateRule(rSrc.GetAt(stIndex));
+		}
+	}
+
+	void FeedbackNotEnoughSpaceRuleList::InsertOrUpdateRule(const FeedbackNotEnoughSpaceRule& rRule)
+	{
+		bool bFound = false;
+		for(size_t stIndex = 0; stIndex < GetCount(); ++stIndex)
+		{
+			FeedbackNotEnoughSpaceRule& rCurrent = GetAt(stIndex);
+			if(rCurrent.HaveSameCondition(rRule))
+			{
+				bFound = true;
+				rCurrent.SetResult(rRule.GetResult());
+			}
+		}
+
+		if(!bFound)
+			InsertAt(0, rRule);
+	}
+
+	void FeedbackNotEnoughSpaceRuleList::InitColumns(const serializer::ISerializerContainerPtr& spContainer) const
+	{
+		IColumnsDefinition& rColumns = spContainer->GetColumnsDefinition();
+		if(rColumns.IsEmpty())
+			TFileFilter::InitColumns(rColumns);
+	}
+
+	void FeedbackNotEnoughSpaceRuleList::StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const
+	{
+		rConfig.DeleteNode(pszNodeName);
+		for(const FeedbackNotEnoughSpaceRule& rRule : m_vEntries)
+		{
+			TConfig cfgNode;
+			rRule.StoreInConfig(cfgNode);
+
+			TString strNode = TString(pszNodeName) + _T(".RuleDefinition");
+			rConfig.AddSubConfig(strNode.c_str(), cfgNode);
+		}
+	}
+
+	bool FeedbackNotEnoughSpaceRuleList::ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName)
+	{
+		m_vEntries.clear();
+
+		TConfigArray vConfigs;
+		if(!rConfig.ExtractMultiSubConfigs(pszNodeName, vConfigs))
+			return false;
+
+		for(size_t stIndex = 0; stIndex < vConfigs.GetCount(); ++stIndex)
+		{
+			const TConfig& rCfg = vConfigs.GetAt(stIndex);
+			FeedbackNotEnoughSpaceRule rule;
+			rule.ReadFromConfig(rCfg);
+
+			m_vEntries.push_back(rule);
+		}
+		return true;
+	}
+}
Index: src/libchengine/FeedbackNotEnoughSpaceRuleList.h
===================================================================
diff -u
--- src/libchengine/FeedbackNotEnoughSpaceRuleList.h	(revision 0)
+++ src/libchengine/FeedbackNotEnoughSpaceRuleList.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "libchengine.h"
+#include "FeedbackNotEnoughSpaceRule.h"
+#include "TConfig.h"
+#include "../libserializer/SerializableContainer.h"
+
+namespace chengine
+{
+#pragma warning(push)
+#pragma warning(disable: 4251)
+
+	class LIBCHENGINE_API FeedbackNotEnoughSpaceRuleList : public serializer::SerializableContainer<FeedbackNotEnoughSpaceRule>
+	{
+	public:
+		EFeedbackResult Matches(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize) const;
+
+		void Merge(const FeedbackNotEnoughSpaceRuleList& rSrc);
+
+		void InitColumns(const serializer::ISerializerContainerPtr& spContainer) const override;
+
+		void StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const;
+		bool ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName);
+
+	private:
+		void InsertOrUpdateRule(const FeedbackNotEnoughSpaceRule& rRule);
+	};
+#pragma warning(pop)
+}
+
+CONFIG_MEMBER_SERIALIZATION(FeedbackNotEnoughSpaceRuleList)
Index: src/libchengine/FeedbackOperationEventRule.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackOperationEventRule.cpp	(revision 0)
+++ src/libchengine/FeedbackOperationEventRule.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,180 @@
+#include "stdafx.h"
+#include "FeedbackOperationEventRule.h"
+#include "../libstring/TString.h"
+#include "../libstring/TStringArray.h"
+#include "../libchcore/TPath.h"
+
+using namespace serializer;
+using namespace string;
+using namespace chcore;
+
+namespace chengine
+{
+	FeedbackOperationEventRule::FeedbackOperationEventRule() :
+		m_bUseOperationEvent(m_setModifications, false),
+		m_eOperationEvent(m_setModifications, eOperationEvent_Finished),
+		m_eResult(m_setModifications, eResult_Unknown)
+	{
+		m_setModifications[FeedbackOperationEventRuleEnum::eMod_Added] = true;
+	}
+
+	FeedbackOperationEventRule::FeedbackOperationEventRule(const FeedbackOperationEventRule& rSrc) :
+		serializer::SerializableObject<FeedbackOperationEventRuleEnum::eMod_Last>(rSrc),
+		m_bUseOperationEvent(rSrc.m_bUseOperationEvent, m_setModifications),
+		m_eOperationEvent(rSrc.m_eOperationEvent, m_setModifications),
+		m_eResult(rSrc.m_eResult, m_setModifications)
+	{
+	}
+
+	FeedbackOperationEventRule& FeedbackOperationEventRule::operator=(const FeedbackOperationEventRule& rSrc)
+	{
+		if(this == &rSrc)
+			return *this;
+
+		__super::operator=(rSrc);
+
+		SetData(rSrc);
+
+		return *this;
+	}
+
+	bool FeedbackOperationEventRule::operator==(const FeedbackOperationEventRule& rSrc) const
+	{
+		if(m_bUseOperationEvent != rSrc.m_bUseOperationEvent)
+			return false;
+		if(m_eOperationEvent != rSrc.m_eOperationEvent)
+			return false;
+
+		if(m_eResult != rSrc.m_eResult)
+			return false;
+
+		return true;
+	}
+
+	bool FeedbackOperationEventRule::operator!=(const FeedbackOperationEventRule& rSrc) const
+	{
+		return !operator==(rSrc);
+	}
+
+	void FeedbackOperationEventRule::SetData(const FeedbackOperationEventRule& rSrc)
+	{
+		if(this == &rSrc)
+			return;
+
+		m_bUseOperationEvent = rSrc.m_bUseOperationEvent;
+		m_eOperationEvent = rSrc.m_eOperationEvent;
+		m_eResult = rSrc.m_eResult;
+	}
+
+	bool FeedbackOperationEventRule::Matches(EOperationEvent eEvent, EFeedbackResult& eResult) const
+	{
+		eResult = eResult_Unknown;
+
+		if(m_bUseOperationEvent)
+		{
+			if(m_eOperationEvent != eEvent)
+				return false;
+		}
+
+		eResult = m_eResult;
+		return true;
+	}
+
+	void FeedbackOperationEventRule::InitColumns(serializer::IColumnsDefinition& rColumns)
+	{
+		rColumns.AddColumn(_T("id"), ColumnType<object_id_t>::value);
+		rColumns.AddColumn(_T("use_operation_event"), IColumnsDefinition::eType_bool);
+		rColumns.AddColumn(_T("operation_event"), IColumnsDefinition::eType_int);
+		rColumns.AddColumn(_T("result"), IColumnsDefinition::eType_int);
+	}
+
+	void FeedbackOperationEventRule::Store(const ISerializerContainerPtr& spContainer) const
+	{
+		bool bAdded = m_setModifications[FeedbackOperationEventRuleEnum::eMod_Added];
+		if(m_setModifications.any())
+		{
+			ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, bAdded);
+
+			if(bAdded || m_setModifications[FeedbackOperationEventRuleEnum::eMod_UseOperationEvent])
+				rRow.SetValue(_T("use_operation_event"), m_bUseOperationEvent);
+			if(bAdded || m_setModifications[FeedbackOperationEventRuleEnum::eMod_OperationEvent])
+				rRow.SetValue(_T("operation_event"), m_eOperationEvent);
+
+			if(bAdded || m_setModifications[FeedbackOperationEventRuleEnum::eMod_Result])
+				rRow.SetValue(_T("result"), m_eResult);
+
+			m_setModifications.reset();
+		}
+	}
+
+	void FeedbackOperationEventRule::Load(const ISerializerRowReaderPtr& spRowReader)
+	{
+		TString strMask;
+
+		spRowReader->GetValue(_T("use_operation_event"), m_bUseOperationEvent.Modify());
+		spRowReader->GetValue(_T("operation_event"), *(int*)&m_eOperationEvent.Modify());
+
+		spRowReader->GetValue(_T("result"), *(int*)&m_eResult.Modify());
+
+		m_setModifications.reset();
+	}
+
+	void FeedbackOperationEventRule::StoreInConfig(TConfig& rConfig) const
+	{
+		SetConfigValue(rConfig, _T("OperationEvent.Use"), m_bUseOperationEvent.Get());
+		SetConfigValue(rConfig, _T("OperationEvent.Value"), m_eOperationEvent.Get());
+
+		SetConfigValue(rConfig, _T("Result"), m_eResult.Get());
+	}
+
+	void FeedbackOperationEventRule::ReadFromConfig(const TConfig& rConfig)
+	{
+		if(!GetConfigValue(rConfig, _T("OperationEvent.Use"), m_bUseOperationEvent.Modify()))
+			m_bUseOperationEvent = false;
+		if(!GetConfigValue(rConfig, _T("OperationEvent.Value"), *(int*)m_eOperationEvent.Modify()))
+			m_eOperationEvent = eOperationEvent_Finished;
+
+		if(!GetConfigValue(rConfig, _T("Result"), *(int*)m_eResult.Modify()))
+			m_eResult = eResult_Unknown;
+	}
+
+	bool FeedbackOperationEventRule::HaveSameCondition(const FeedbackOperationEventRule& rSrc) const
+	{
+		if(m_bUseOperationEvent != rSrc.m_bUseOperationEvent)
+			return false;
+		else if(m_bUseOperationEvent == true && m_eOperationEvent != rSrc.m_eOperationEvent)
+			return false;
+
+		return true;
+	}
+
+	bool FeedbackOperationEventRule::GetUseOperationEvent() const
+	{
+		return m_bUseOperationEvent;
+	}
+
+	void FeedbackOperationEventRule::SetUseOperationEventType(bool bUseOperationEvent)
+	{
+		m_bUseOperationEvent = bUseOperationEvent;
+	}
+
+	EOperationEvent FeedbackOperationEventRule::GetOperationEvent() const
+	{
+		return m_eOperationEvent;
+	}
+
+	void FeedbackOperationEventRule::SetOperationEvent(EOperationEvent eOperationEvent)
+	{
+		m_eOperationEvent = eOperationEvent;
+	}
+
+	chengine::EFeedbackResult FeedbackOperationEventRule::GetResult() const
+	{
+		return m_eResult;
+	}
+
+	void FeedbackOperationEventRule::SetResult(EFeedbackResult eResult)
+	{
+		m_eResult = eResult;
+	}
+}
Index: src/libchengine/FeedbackOperationEventRule.h
===================================================================
diff -u
--- src/libchengine/FeedbackOperationEventRule.h	(revision 0)
+++ src/libchengine/FeedbackOperationEventRule.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "libchengine.h"
+#include "../libserializer/SerializableObject.h"
+#include "../libstring/TStringPatternArray.h"
+#include "ECompareType.h"
+#include "EFeedbackResult.h"
+#include "../libserializer/SerializerDataTypes.h"
+#include <bitset>
+#include "../libserializer/TSharedModificationTracker.h"
+#include "TFileInfo.h"
+#include "TConfig.h"
+#include "EFileError.h"
+#include "EOperationEvent.h"
+
+namespace chengine
+{
+	namespace FeedbackOperationEventRuleEnum
+	{
+		enum EModifications
+		{
+			eMod_Added,
+			eMod_UseOperationEvent,
+			eMod_OperationEvent,
+			eMod_Result,
+
+			eMod_Last
+		};
+	}
+
+#pragma warning(push)
+#pragma warning(disable: 4251)
+	class LIBCHENGINE_API FeedbackOperationEventRule : public serializer::SerializableObject<FeedbackOperationEventRuleEnum::eMod_Last>
+	{
+	public:
+		FeedbackOperationEventRule();
+		FeedbackOperationEventRule(const FeedbackOperationEventRule& rSrc);
+		FeedbackOperationEventRule& operator=(const FeedbackOperationEventRule& rSrc);
+
+		bool operator==(const FeedbackOperationEventRule& rSrc) const;
+		bool operator!=(const FeedbackOperationEventRule& rSrc) const;
+
+		void SetData(const FeedbackOperationEventRule& rSrc);
+
+		bool Matches(EOperationEvent eEvent, EFeedbackResult& eResult) const;
+
+		void Store(const serializer::ISerializerContainerPtr& spContainer) const override;
+		void Load(const serializer::ISerializerRowReaderPtr& spRowReader) override;
+		static void InitColumns(serializer::IColumnsDefinition& rColumns);
+
+		void StoreInConfig(TConfig& rConfig) const;
+		void ReadFromConfig(const TConfig& rConfig);
+
+		// comparison
+		bool HaveSameCondition(const FeedbackOperationEventRule& rSrc) const;
+
+		// attributes
+		bool GetUseOperationEvent() const;
+		void SetUseOperationEventType(bool bUseErrorType);
+		EOperationEvent GetOperationEvent() const;
+		void SetOperationEvent(EOperationEvent eErrorType);
+
+		EFeedbackResult GetResult() const;
+		void SetResult(EFeedbackResult eResult);
+
+	private:
+		serializer::TSharedModificationTracker<bool, Bitset, FeedbackOperationEventRuleEnum::eMod_UseOperationEvent> m_bUseOperationEvent;
+		serializer::TSharedModificationTracker<EOperationEvent, Bitset, FeedbackOperationEventRuleEnum::eMod_OperationEvent> m_eOperationEvent;
+
+		serializer::TSharedModificationTracker<EFeedbackResult, Bitset, FeedbackOperationEventRuleEnum::eMod_Result> m_eResult;
+	};
+#pragma warning(pop)
+}
Index: src/libchengine/FeedbackOperationEventRuleList.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackOperationEventRuleList.cpp	(revision 0)
+++ src/libchengine/FeedbackOperationEventRuleList.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,90 @@
+#include "stdafx.h"
+#include "FeedbackOperationEventRuleList.h"
+#include "TConfigArray.h"
+#include "../libserializer/IColumnsDefinition.h"
+#include "TFileFilter.h"
+
+using namespace string;
+using namespace serializer;
+
+namespace chengine
+{
+	EFeedbackResult FeedbackOperationEventRuleList::Matches(EOperationEvent eEvent) const
+	{
+		if(m_vEntries.empty())
+			return eResult_Unknown;
+
+		for(const FeedbackOperationEventRule& rRule : m_vEntries)
+		{
+			EFeedbackResult eResult = eResult_Unknown;
+			if(rRule.Matches(eEvent, eResult))
+				return eResult;
+		}
+
+		return eResult_Unknown;
+	}
+
+	void FeedbackOperationEventRuleList::Merge(const FeedbackOperationEventRuleList& rSrc)
+	{
+		for(size_t stIndex = 0; stIndex < rSrc.GetCount(); ++stIndex)
+		{
+			InsertOrUpdateRule(rSrc.GetAt(stIndex));
+		}
+	}
+
+	void FeedbackOperationEventRuleList::InsertOrUpdateRule(const FeedbackOperationEventRule& rRule)
+	{
+		bool bFound = false;
+		for(size_t stIndex = 0; stIndex < GetCount(); ++stIndex)
+		{
+			FeedbackOperationEventRule& rCurrent = GetAt(stIndex);
+			if(rCurrent.HaveSameCondition(rRule))
+			{
+				bFound = true;
+				rCurrent.SetResult(rRule.GetResult());
+			}
+		}
+
+		if(!bFound)
+			InsertAt(0, rRule);
+	}
+
+	void FeedbackOperationEventRuleList::InitColumns(const serializer::ISerializerContainerPtr& spContainer) const
+	{
+		IColumnsDefinition& rColumns = spContainer->GetColumnsDefinition();
+		if(rColumns.IsEmpty())
+			TFileFilter::InitColumns(rColumns);
+	}
+
+	void FeedbackOperationEventRuleList::StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const
+	{
+		rConfig.DeleteNode(pszNodeName);
+		for(const FeedbackOperationEventRule& rRule : m_vEntries)
+		{
+			TConfig cfgNode;
+			rRule.StoreInConfig(cfgNode);
+
+			TString strNode = TString(pszNodeName) + _T(".RuleDefinition");
+			rConfig.AddSubConfig(strNode.c_str(), cfgNode);
+		}
+	}
+
+	bool FeedbackOperationEventRuleList::ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName)
+	{
+		m_vEntries.clear();
+
+		TConfigArray vConfigs;
+		if(!rConfig.ExtractMultiSubConfigs(pszNodeName, vConfigs))
+			return false;
+
+		for(size_t stIndex = 0; stIndex < vConfigs.GetCount(); ++stIndex)
+		{
+			const TConfig& rCfg = vConfigs.GetAt(stIndex);
+			FeedbackOperationEventRule rule;
+			rule.ReadFromConfig(rCfg);
+
+			m_vEntries.push_back(rule);
+		}
+		return true;
+	}
+}
Index: src/libchengine/FeedbackOperationEventRuleList.h
===================================================================
diff -u
--- src/libchengine/FeedbackOperationEventRuleList.h	(revision 0)
+++ src/libchengine/FeedbackOperationEventRuleList.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "libchengine.h"
+#include "FeedbackOperationEventRule.h"
+#include "TConfig.h"
+#include "../libserializer/SerializableContainer.h"
+
+namespace chengine
+{
+#pragma warning(push)
+#pragma warning(disable: 4251)
+
+	class LIBCHENGINE_API FeedbackOperationEventRuleList : public serializer::SerializableContainer<FeedbackOperationEventRule>
+	{
+	public:
+		EFeedbackResult Matches(EOperationEvent eEvent) const;
+
+		void Merge(const FeedbackOperationEventRuleList& rSrc);
+
+		void InitColumns(const serializer::ISerializerContainerPtr& spContainer) const override;
+
+		void StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const;
+		bool ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName);
+
+	private:
+		void InsertOrUpdateRule(const FeedbackOperationEventRule& rRule);
+	};
+#pragma warning(pop)
+}
+
+CONFIG_MEMBER_SERIALIZATION(FeedbackOperationEventRuleList)
Index: src/libchengine/FeedbackPredefinedRules.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackPredefinedRules.cpp	(revision 0)
+++ src/libchengine/FeedbackPredefinedRules.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,89 @@
+#include "stdafx.h"
+#include "FeedbackPredefinedRules.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+
+namespace chengine
+{
+	FeedbackAlreadyExistsRuleList FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition eCondition, EFeedbackResult eResult)
+	{
+		FeedbackAlreadyExistsRuleList ruleList;
+
+		switch(eCondition)
+		{
+		case EPredefinedRuleCondition::eCondition_ApplyToAll:
+		{
+			FeedbackAlreadyExistsRule rule;
+			rule.SetResult(eResult);
+			ruleList.Add(rule);
+			break;
+		}
+		case EPredefinedRuleCondition::eCondition_WhenDifferentDateOrSize:
+		{
+			FeedbackAlreadyExistsRule rule;
+			rule.SetResult(eResult);
+			rule.SetUseDateCompare(true);
+			rule.SetDateCompareType(eCmp_NotEqual);
+			ruleList.Add(rule);
+
+			FeedbackAlreadyExistsRule rule2;
+			rule2.SetResult(eResult);
+			rule2.SetUseSizeCompare(true);
+			rule2.SetSizeCompareType(eCmp_NotEqual);
+			ruleList.Add(rule2);
+
+			break;
+		}
+		case EPredefinedRuleCondition::eCondition_WhenSameDateAndSize:
+		{
+			FeedbackAlreadyExistsRule rule;
+			rule.SetResult(eResult);
+			rule.SetUseDateCompare(true);
+			rule.SetDateCompareType(eCmp_Equal);
+			rule.SetUseSizeCompare(true);
+			rule.SetSizeCompareType(eCmp_Equal);
+			ruleList.Add(rule);
+			break;
+		}
+		case EPredefinedRuleCondition::eCondition_WhenNewerThanDst:
+		{
+			FeedbackAlreadyExistsRule rule;
+			rule.SetResult(eResult);
+			rule.SetUseDateCompare(true);
+			rule.SetDateCompareType(eCmp_Greater);
+			ruleList.Add(rule);
+			break;
+		}
+		case EPredefinedRuleCondition::eCondition_WhenOlderThanDst:
+		{
+			FeedbackAlreadyExistsRule rule;
+			rule.SetResult(eResult);
+			rule.SetUseDateCompare(true);
+			rule.SetDateCompareType(eCmp_Less);
+			ruleList.Add(rule);
+			break;
+		}
+		case EPredefinedRuleCondition::eCondition_WhenSmallerThanDst:
+		{
+			FeedbackAlreadyExistsRule rule;
+			rule.SetResult(eResult);
+			rule.SetUseSizeCompare(true);
+			rule.SetSizeCompareType(eCmp_Less);
+			ruleList.Add(rule);
+			break;
+		}
+		case EPredefinedRuleCondition::eCondition_WhenBiggerThanDst:
+		{
+			FeedbackAlreadyExistsRule rule;
+			rule.SetResult(eResult);
+			rule.SetUseSizeCompare(true);
+			rule.SetSizeCompareType(eCmp_Greater);
+			ruleList.Add(rule);
+			break;
+		}
+		default:
+			throw std::runtime_error("Unhandled predefined rule condition");
+		}
+
+		return ruleList;
+	}
+}
Index: src/libchengine/FeedbackPredefinedRules.h
===================================================================
diff -u
--- src/libchengine/FeedbackPredefinedRules.h	(revision 0)
+++ src/libchengine/FeedbackPredefinedRules.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "libchengine.h"
+#include "EFeedbackResult.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+
+namespace chengine
+{
+	enum class EPredefinedRuleCondition
+	{
+		eCondition_ApplyToAll,
+
+		eCondition_WhenDifferentDateOrSize,
+		eCondition_WhenSameDateAndSize,
+
+		eCondition_WhenNewerThanDst,
+		eCondition_WhenOlderThanDst,
+
+		eCondition_WhenSmallerThanDst,
+		eCondition_WhenBiggerThanDst
+	};
+
+	class LIBCHENGINE_API FeedbackPredefinedRules
+	{
+	public:
+		static FeedbackAlreadyExistsRuleList CreateAlreadyExistsRule(EPredefinedRuleCondition eCondition, EFeedbackResult eResult);
+	};
+}
Fisheye: Tag 08717141ce5f6926116c298cbc9442094a45bb67 refers to a dead (removed) revision in file `src/libchengine/FeedbackRuleList.cpp'.
Fisheye: No comparison available.  Pass `N' to diff?
Index: src/libchengine/FeedbackRules.cpp
===================================================================
diff -u
--- src/libchengine/FeedbackRules.cpp	(revision 0)
+++ src/libchengine/FeedbackRules.cpp	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,119 @@
+#include "stdafx.h"
+#include "FeedbackRules.h"
+#include "../libserializer/ISerializerContainer.h"
+
+using namespace serializer;
+
+void chengine::FeedbackRules::Store(const serializer::ISerializerPtr& spSerializer) const
+{
+	ISerializerContainerPtr spContainer = spSerializer->GetContainer(L"feedback_error");
+	m_feedbackErrorRules.Store(spContainer);
+
+	spContainer = spSerializer->GetContainer(L"feedback_already_exists");
+	m_feedbackAlreadyExistsRules.Store(spContainer);
+
+	spContainer = spSerializer->GetContainer(L"feedback_not_enough_space");
+	m_feedbackNotEnoughSpaceRules.Store(spContainer);
+
+	spContainer = spSerializer->GetContainer(L"feedback_operation_event");
+	m_feedbackOperationEventRules.Store(spContainer);
+}
+
+void chengine::FeedbackRules::Load(const serializer::ISerializerPtr& spSerializer)
+{
+	ISerializerContainerPtr spContainer = spSerializer->GetContainer(L"feedback_error");
+	m_feedbackErrorRules.Load(spContainer);
+
+	spContainer = spSerializer->GetContainer(L"feedback_already_exists");
+	m_feedbackAlreadyExistsRules.Load(spContainer);
+
+	spContainer = spSerializer->GetContainer(L"feedback_not_enough_space");
+	m_feedbackNotEnoughSpaceRules.Load(spContainer);
+
+	spContainer = spSerializer->GetContainer(L"feedback_operation_event");
+	m_feedbackOperationEventRules.Load(spContainer);
+}
+
+void chengine::FeedbackRules::StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const
+{
+	std::wstring strNode = pszNodeName;
+	std::wstring strNewNode = strNode + L".AlreadyExists";
+	m_feedbackAlreadyExistsRules.StoreInConfig(rConfig, strNewNode.c_str());
+
+	strNewNode = strNewNode + L".Error";
+	m_feedbackErrorRules.StoreInConfig(rConfig, strNewNode.c_str());
+
+	strNewNode = strNewNode + L".NotEnoughSpace";
+	m_feedbackNotEnoughSpaceRules.StoreInConfig(rConfig, strNewNode.c_str());
+
+	strNewNode = strNewNode + L".OperationEvent";
+	m_feedbackOperationEventRules.StoreInConfig(rConfig, strNewNode.c_str());
+}
+
+bool chengine::FeedbackRules::ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName)
+{
+	bool bResult = true;
+
+	std::wstring strNode = pszNodeName;
+	std::wstring strNewNode = strNode + L".AlreadyExists";
+	bResult &= m_feedbackAlreadyExistsRules.ReadFromConfig(rConfig, strNewNode.c_str());
+
+	strNewNode = strNewNode + L".Error";
+	bResult &= m_feedbackErrorRules.ReadFromConfig(rConfig, strNewNode.c_str());
+
+	strNewNode = strNewNode + L".NotEnoughSpace";
+	bResult &= m_feedbackNotEnoughSpaceRules.ReadFromConfig(rConfig, strNewNode.c_str());
+
+	strNewNode = strNewNode + L".OperationEvent";
+	bResult &= m_feedbackOperationEventRules.ReadFromConfig(rConfig, strNewNode.c_str());
+
+	return bResult;
+}
+
+void chengine::FeedbackRules::Clear()
+{
+	m_feedbackAlreadyExistsRules.Clear();
+	m_feedbackErrorRules.Clear();
+	m_feedbackNotEnoughSpaceRules.Clear();
+	m_feedbackOperationEventRules.Clear();
+}
+
+const chengine::FeedbackAlreadyExistsRuleList& chengine::FeedbackRules::GetAlreadyExistsRules() const
+{
+	return m_feedbackAlreadyExistsRules;
+}
+
+const chengine::FeedbackErrorRuleList& chengine::FeedbackRules::GetErrorRules() const
+{
+	return m_feedbackErrorRules;
+}
+
+const chengine::FeedbackNotEnoughSpaceRuleList& chengine::FeedbackRules::GetNotEnoughSpaceRules() const
+{
+	return m_feedbackNotEnoughSpaceRules;
+}
+
+const chengine::FeedbackOperationEventRuleList& chengine::FeedbackRules::GetOperationEventRules() const
+{
+	return m_feedbackOperationEventRules;
+}
+
+chengine::FeedbackOperationEventRuleList& chengine::FeedbackRules::GetOperationEventRules()
+{
+	return m_feedbackOperationEventRules;
+}
+
+chengine::FeedbackNotEnoughSpaceRuleList& chengine::FeedbackRules::GetNotEnoughSpaceRules()
+{
+	return m_feedbackNotEnoughSpaceRules;
+}
+
+chengine::FeedbackErrorRuleList& chengine::FeedbackRules::GetErrorRules()
+{
+	return m_feedbackErrorRules;
+}
+
+chengine::FeedbackAlreadyExistsRuleList& chengine::FeedbackRules::GetAlreadyExistsRules()
+{
+	return m_feedbackAlreadyExistsRules;
+}
Index: src/libchengine/FeedbackRules.h
===================================================================
diff -u
--- src/libchengine/FeedbackRules.h	(revision 0)
+++ src/libchengine/FeedbackRules.h	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "libchengine.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+#include "FeedbackErrorRuleList.h"
+#include "FeedbackNotEnoughSpaceRuleList.h"
+#include "FeedbackOperationEventRuleList.h"
+#include "../libserializer/ISerializer.h"
+#include "TConfig.h"
+
+namespace chengine
+{
+	class LIBCHENGINE_API FeedbackRules
+	{
+	public:
+		// serialization
+		void Store(const serializer::ISerializerPtr& spSerializer) const;
+		void Load(const serializer::ISerializerPtr& spSerializer);
+
+		void StoreInConfig(TConfig& rConfig, PCTSTR pszNodeName) const;
+		bool ReadFromConfig(const TConfig& rConfig, PCTSTR pszNodeName);
+
+		void Clear();
+
+		const FeedbackAlreadyExistsRuleList& GetAlreadyExistsRules() const;
+		FeedbackAlreadyExistsRuleList& GetAlreadyExistsRules();
+
+		const FeedbackErrorRuleList& GetErrorRules() const;
+		FeedbackErrorRuleList& GetErrorRules();
+
+		const FeedbackNotEnoughSpaceRuleList& GetNotEnoughSpaceRules() const;
+		FeedbackNotEnoughSpaceRuleList& GetNotEnoughSpaceRules();
+
+		const FeedbackOperationEventRuleList& GetOperationEventRules() const;
+		FeedbackOperationEventRuleList& GetOperationEventRules();
+
+	private:
+		FeedbackAlreadyExistsRuleList m_feedbackAlreadyExistsRules;
+		FeedbackErrorRuleList m_feedbackErrorRules;
+		FeedbackNotEnoughSpaceRuleList m_feedbackNotEnoughSpaceRules;
+		FeedbackOperationEventRuleList m_feedbackOperationEventRules;
+	};
+}
+
+CONFIG_MEMBER_SERIALIZATION(FeedbackRules)
Index: src/libchengine/IFeedbackHandler.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/IFeedbackHandler.h	(.../IFeedbackHandler.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/IFeedbackHandler.h	(.../IFeedbackHandler.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -23,6 +23,11 @@
 #include "TFeedbackResult.h"
 #include "../libstring/TString.h"
 #include "../libserializer/ISerializerContainer.h"
+#include "EOperationEvent.h"
+#include "FeedbackErrorRuleList.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+#include "FeedbackNotEnoughSpaceRuleList.h"
+#include "FeedbackOperationEventRuleList.h"
 
 namespace chengine
 {
@@ -33,24 +38,10 @@
 	public:
 		virtual ~IFeedbackHandler();
 
-		// requests with some processing data
-		virtual TFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eFileError, unsigned long ulError) = 0;
-		virtual TFeedbackResult FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo) = 0;
-		virtual TFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize) = 0;
-
-		// no-data requests
-		virtual TFeedbackResult OperationFinished() = 0;
-		virtual TFeedbackResult OperationError() = 0;
-
-		// retry interval (in ms)
-		virtual DWORD GetRetryInterval() const = 0;
-
-		// reset permanent states
-		virtual void RestoreDefaults() = 0;
-
-		//serialization
-		virtual void Store(const serializer::ISerializerContainerPtr& spContainer) const = 0;
-		virtual void Load(const serializer::ISerializerContainerPtr& spContainer) = 0;
+		virtual EFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eFileError, unsigned long ulError, FeedbackErrorRuleList& rNewRules) = 0;
+		virtual EFeedbackResult FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo, FeedbackAlreadyExistsRuleList& rNewRules) = 0;
+		virtual EFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize, FeedbackNotEnoughSpaceRuleList& rNewRules) = 0;
+		virtual EFeedbackResult OperationEvent(EOperationEvent eEvent, FeedbackOperationEventRuleList& rNewRules) = 0;
 	};
 
 	typedef std::shared_ptr<IFeedbackHandler> IFeedbackHandlerPtr;
Fisheye: Tag 08717141ce5f6926116c298cbc9442094a45bb67 refers to a dead (removed) revision in file `src/libchengine/TFeedbackHandlerBase.cpp'.
Fisheye: No comparison available.  Pass `N' to diff?
Fisheye: Tag 08717141ce5f6926116c298cbc9442094a45bb67 refers to a dead (removed) revision in file `src/libchengine/TFeedbackHandlerBase.h'.
Fisheye: No comparison available.  Pass `N' to diff?
Fisheye: Tag 08717141ce5f6926116c298cbc9442094a45bb67 refers to a dead (removed) revision in file `src/libchengine/TFeedbackHandlerWrapper.cpp'.
Fisheye: No comparison available.  Pass `N' to diff?
Fisheye: Tag 08717141ce5f6926116c298cbc9442094a45bb67 refers to a dead (removed) revision in file `src/libchengine/TFeedbackHandlerWrapper.h'.
Fisheye: No comparison available.  Pass `N' to diff?
Index: src/libchengine/TFilesystemFeedbackWrapper.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TFilesystemFeedbackWrapper.cpp	(.../TFilesystemFeedbackWrapper.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TFilesystemFeedbackWrapper.cpp	(.../TFilesystemFeedbackWrapper.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -28,8 +28,8 @@
 
 namespace chengine
 {
-	TFilesystemFeedbackWrapper::TFilesystemFeedbackWrapper(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemPtr& spFilesystem, const logger::TLogFileDataPtr& spLogFileData, TWorkerThreadController& rThreadController) :
-		m_spFeedbackHandler(spFeedbackHandler),
+	TFilesystemFeedbackWrapper::TFilesystemFeedbackWrapper(const FeedbackManagerPtr& spFeedbackManager, const IFilesystemPtr& spFilesystem, const logger::TLogFileDataPtr& spLogFileData, TWorkerThreadController& rThreadController) :
+		m_spFeedbackManager(spFeedbackManager),
 		m_spFilesystem(spFilesystem),
 		m_spLog(logger::MakeLogger(spLogFileData, L"Filesystem")),
 		m_rThreadController(rThreadController)
@@ -64,7 +64,7 @@
 			strFormat.Replace(_T("%path"), pathDirectory.ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(pathDirectory.ToWString(), TString(), EFileError::eCreateError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(pathDirectory.ToWString(), TString(), EFileError::eCreateError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -95,7 +95,7 @@
 
 	bool TFilesystemFeedbackWrapper::WasKillRequested(const TFeedbackResult& rFeedbackResult) const
 	{
-		if(m_rThreadController.KillRequested(rFeedbackResult.IsAutomatedReply() ? m_spFeedbackHandler->GetRetryInterval() : 0))
+		if(m_rThreadController.KillRequested(rFeedbackResult.IsAutomatedReply() ? m_spFeedbackManager->GetRetryInterval() : 0))
 			return true;
 		return false;
 	}
@@ -133,7 +133,7 @@
 				strFormat.Replace(_T("%path"), pathDestination.ToString());
 				LOG_ERROR(m_spLog) << strFormat.c_str();
 
-				frResult = m_spFeedbackHandler->FileError(pathDestination.ToWString(), TString(), EFileError::eCheckForFreeSpace, dwLastError);
+				frResult = m_spFeedbackManager->FileError(pathDestination.ToWString(), TString(), EFileError::eCheckForFreeSpace, dwLastError);
 				switch (frResult.GetResult())
 				{
 				case eResult_Cancel:
@@ -162,7 +162,7 @@
 				strFormat.Replace(_T("%availablesize"), boost::lexical_cast<std::wstring>(ullAvailableSize).c_str());
 				LOG_WARNING(m_spLog) << strFormat.c_str();
 
-				frResult = m_spFeedbackHandler->NotEnoughSpace(pathFirstSrc.ToWString(), pathDestination.ToWString(), ullNeededSize);
+				frResult = m_spFeedbackManager->NotEnoughSpace(pathFirstSrc.ToWString(), pathDestination.ToWString(), ullNeededSize);
 				switch (frResult.GetResult())
 				{
 				case eResult_Cancel:
@@ -222,7 +222,7 @@
 			strFormat.Replace(_T("%path"), spFileInfo->GetFullFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(spFileInfo->GetFullFilePath().ToWString(), TString(), EFileError::eDeleteError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(spFileInfo->GetFullFilePath().ToWString(), TString(), EFileError::eDeleteError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -281,7 +281,7 @@
 			strFormat.Replace(_T("%path"), spFileInfo->GetFullFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(spFileInfo->GetFullFilePath().ToWString(), TString(), EFileError::eDeleteError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(spFileInfo->GetFullFilePath().ToWString(), TString(), EFileError::eDeleteError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -343,7 +343,7 @@
 			strFormat.Replace(_T("%dstpath"), pathDestination.ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(pathSrc.ToWString(), pathDestination.ToWString(), EFileError::eFastMoveError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(pathSrc.ToWString(), pathDestination.ToWString(), EFileError::eFastMoveError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -389,7 +389,7 @@
 				dwLastError = e.GetNativeError();
 			}
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(pathCurrent.ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(pathCurrent.ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -436,7 +436,7 @@
 				dwLastError = e.GetNativeError();
 			}
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(pathFileDir.ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(pathFileDir.ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
 			switch(frResult.GetResult())
 			{
 			case eResult_Cancel:
Index: src/libchengine/TFilesystemFeedbackWrapper.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TFilesystemFeedbackWrapper.h	(.../TFilesystemFeedbackWrapper.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TFilesystemFeedbackWrapper.h	(.../TFilesystemFeedbackWrapper.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -22,6 +22,7 @@
 #include "IFilesystem.h"
 #include "TSubTaskBase.h"
 #include "../liblogger/TLogger.h"
+#include "FeedbackManager.h"
 
 namespace chcore {
 	class TWorkerThreadController;
@@ -32,7 +33,7 @@
 	class TFilesystemFeedbackWrapper
 	{
 	public:
-		TFilesystemFeedbackWrapper(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemPtr& spFilesystem,
+		TFilesystemFeedbackWrapper(const FeedbackManagerPtr& spFeedbackManager, const IFilesystemPtr& spFilesystem,
 			const logger::TLogFileDataPtr& spLogFileData, chcore::TWorkerThreadController& rThreadController);
 		TFilesystemFeedbackWrapper& operator=(const TFilesystemFeedbackWrapper&) = delete;
 
@@ -56,7 +57,7 @@
 		bool WasKillRequested(const TFeedbackResult& rFeedbackResult) const;
 
 	private:
-		IFeedbackHandlerPtr m_spFeedbackHandler;
+		FeedbackManagerPtr m_spFeedbackManager;
 		IFilesystemPtr m_spFilesystem;
 		logger::TLoggerPtr m_spLog;
 		chcore::TWorkerThreadController& m_rThreadController;
Index: src/libchengine/TFilesystemFileFeedbackWrapper.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TFilesystemFileFeedbackWrapper.cpp	(.../TFilesystemFileFeedbackWrapper.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TFilesystemFileFeedbackWrapper.cpp	(.../TFilesystemFileFeedbackWrapper.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -30,15 +30,15 @@
 namespace chengine
 {
 	TFilesystemFileFeedbackWrapper::TFilesystemFileFeedbackWrapper(const IFilesystemFilePtr& spFile, 
-		const IFeedbackHandlerPtr& spFeedbackHandler, const logger::TLogFileDataPtr& spLogFileData,
+		const FeedbackManagerPtr& spFeedbackManager, const logger::TLogFileDataPtr& spLogFileData,
 		TWorkerThreadController& rThreadController, const IFilesystemPtr& spFilesystem) :
 		m_spFile(spFile),
-		m_spFeedbackHandler(spFeedbackHandler),
+		m_spFeedbackManager(spFeedbackManager),
 		m_spFilesystem(spFilesystem),
 		m_spLog(std::make_unique<logger::TLogger>(spLogFileData, L"Filesystem-File")),
 		m_rThreadController(rThreadController)
 	{
-		if (!spFeedbackHandler)
+		if (!spFeedbackManager)
 			throw TCoreException(eErr_InvalidArgument, L"spFeedbackHandler is NULL", LOCATION);
 		if (!spFile)
 			throw TCoreException(eErr_InvalidArgument, L"spFile is NULL", LOCATION);
@@ -55,7 +55,7 @@
 		m_spFile->GetFileInfo(tDstFileInfo);
 
 		// src and dst files are the same
-		TFeedbackResult frResult = m_spFeedbackHandler->FileAlreadyExists(*spSrcFileInfo, tDstFileInfo);
+		TFeedbackResult frResult = m_spFeedbackManager->FileAlreadyExists(*spSrcFileInfo, tDstFileInfo);
 		switch(frResult.GetResult())
 		{
 		case eResult_Overwrite:
@@ -109,7 +109,7 @@
 			strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eResizeError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eResizeError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -161,7 +161,7 @@
 			strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eReadError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eReadError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -213,7 +213,7 @@
 			strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eWriteError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eWriteError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -264,7 +264,7 @@
 			strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eFinalizeError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eFinalizeError, dwLastError);
 			switch (frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -323,7 +323,7 @@
 		strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 		LOG_ERROR(m_spLog) << strFormat.c_str();
 
-		TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eReadError, dwLastError);
+		TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eReadError, dwLastError);
 		switch(frResult.GetResult())
 		{
 		case eResult_Cancel:
@@ -355,7 +355,7 @@
 		strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 		LOG_ERROR(m_spLog) << strFormat.c_str();
 
-		TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eWriteError, dwLastError);
+		TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eWriteError, dwLastError);
 		switch(frResult.GetResult())
 		{
 		case eResult_Cancel:
@@ -398,7 +398,7 @@
 			strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError);
 			switch(frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -457,7 +457,7 @@
 			if(bSilent)
 				return TSubTaskBase::eSubResult_Error;
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
 			switch(frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -513,7 +513,7 @@
 			strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString());
 			LOG_ERROR(m_spLog) << strFormat.c_str();
 
-			TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
+			TFeedbackResult frResult = m_spFeedbackManager->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eRetrieveFileInfo, dwLastError);
 			switch(frResult.GetResult())
 			{
 			case eResult_Cancel:
@@ -544,7 +544,7 @@
 
 	bool TFilesystemFileFeedbackWrapper::WasKillRequested(const TFeedbackResult& rFeedbackResult) const
 	{
-		if(m_rThreadController.KillRequested(rFeedbackResult.IsAutomatedReply() ? m_spFeedbackHandler->GetRetryInterval() : 0))
+		if(m_rThreadController.KillRequested(rFeedbackResult.IsAutomatedReply() ? m_spFeedbackManager->GetRetryInterval() : 0))
 			return true;
 		return false;
 	}
Index: src/libchengine/TFilesystemFileFeedbackWrapper.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TFilesystemFileFeedbackWrapper.h	(.../TFilesystemFileFeedbackWrapper.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TFilesystemFileFeedbackWrapper.h	(.../TFilesystemFileFeedbackWrapper.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -21,9 +21,9 @@
 
 #include "IFilesystemFile.h"
 #include "TSubTaskBase.h"
-#include "IFeedbackHandler.h"
 #include "IFilesystem.h"
 #include "../liblogger/TLogger.h"
+#include "FeedbackManager.h"
 
 namespace chcore
 {
@@ -35,7 +35,7 @@
 	class TFilesystemFileFeedbackWrapper
 	{
 	public:
-		TFilesystemFileFeedbackWrapper(const IFilesystemFilePtr& spFile, const IFeedbackHandlerPtr& spFeedbackHandler,
+		TFilesystemFileFeedbackWrapper(const IFilesystemFilePtr& spFile, const FeedbackManagerPtr& spFeedbackManager,
 			const logger::TLogFileDataPtr& spLogFileData, chcore::TWorkerThreadController& rThreadController,
 			const IFilesystemPtr& spFilesystem);
 		TFilesystemFileFeedbackWrapper& operator=(const TFilesystemFileFeedbackWrapper&) = delete;
@@ -70,7 +70,7 @@
 
 	private:
 		IFilesystemFilePtr m_spFile;
-		IFeedbackHandlerPtr m_spFeedbackHandler;
+		FeedbackManagerPtr m_spFeedbackManager;
 		IFilesystemPtr m_spFilesystem;
 		logger::TLoggerPtr m_spLog;
 		chcore::TWorkerThreadController& m_rThreadController;
Index: src/libchengine/TOverlappedReaderFB.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TOverlappedReaderFB.cpp	(.../TOverlappedReaderFB.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TOverlappedReaderFB.cpp	(.../TOverlappedReaderFB.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -27,7 +27,7 @@
 namespace chengine
 {
 	TOverlappedReaderFB::TOverlappedReaderFB(const IFilesystemPtr& spFilesystem,
-		const IFeedbackHandlerPtr& spFeedbackHandler,
+		const FeedbackManagerPtr& spFeedbackManager,
 		TWorkerThreadController& rThreadController,
 		const TSubTaskStatsInfoPtr& spStats,
 		const TFileInfoPtr& spSrcFileInfo,
@@ -50,7 +50,7 @@
 		m_rThreadController(rThreadController),
 		m_spLog(logger::MakeLogger(spLogFileData, L"File-Reader"))
 	{
-		if(!spFeedbackHandler)
+		if(!spFeedbackManager)
 			throw TCoreException(eErr_InvalidArgument, L"spFeedbackHandler is NULL", LOCATION);
 		if(!spFilesystem)
 			throw TCoreException(eErr_InvalidArgument, L"spFilesystem is NULL", LOCATION);
@@ -66,7 +66,7 @@
 			throw TCoreException(eErr_InvalidArgument, L"spDataRange is NULL", LOCATION);
 
 		IFilesystemFilePtr fileSrc = m_spFilesystem->CreateFileObject(IFilesystemFile::eMode_Read, m_spSrcFileInfo->GetFullFilePath(), bNoBuffering, bProtectReadOnlyFiles);
-		m_spSrcFile = std::make_shared<TFilesystemFileFeedbackWrapper>(fileSrc, spFeedbackHandler, spLogFileData, rThreadController, spFilesystem);
+		m_spSrcFile = std::make_shared<TFilesystemFileFeedbackWrapper>(fileSrc, spFeedbackManager, spLogFileData, rThreadController, spFilesystem);
 	}
 
 	TOverlappedReaderFB::~TOverlappedReaderFB()
Index: src/libchengine/TOverlappedReaderFB.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TOverlappedReaderFB.h	(.../TOverlappedReaderFB.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TOverlappedReaderFB.h	(.../TOverlappedReaderFB.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -32,7 +32,7 @@
 	{
 	public:
 		TOverlappedReaderFB(const IFilesystemPtr& spFilesystem,
-			const IFeedbackHandlerPtr& spFeedbackHandler,
+			const FeedbackManagerPtr& spFeedbackManager,
 		    chcore::TWorkerThreadController& rThreadController,
 			const TSubTaskStatsInfoPtr& spStats,
 			const TFileInfoPtr& spSrcFileInfo,
Index: src/libchengine/TOverlappedReaderWriterFB.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TOverlappedReaderWriterFB.cpp	(.../TOverlappedReaderWriterFB.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TOverlappedReaderWriterFB.cpp	(.../TOverlappedReaderWriterFB.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -24,7 +24,7 @@
 namespace chengine
 {
 	TOverlappedReaderWriterFB::TOverlappedReaderWriterFB(const IFilesystemPtr& spFilesystem,
-		const IFeedbackHandlerPtr& spFeedbackHandler,
+		const FeedbackManagerPtr& spFeedbackManager,
 		TWorkerThreadController& rThreadController,
 		TOverlappedThreadPool& rThreadPool,
 		const TFileInfoPtr& spSrcFileInfo,
@@ -47,8 +47,8 @@
 		m_rThreadController(rThreadController),
 		m_spRange(std::make_shared<TOverlappedProcessorRange>(ullResumePosition)),
 		m_spMemoryPool(spMemoryPool),
-		m_spReader(std::make_shared<TOverlappedReaderFB>(spFilesystem, spFeedbackHandler, rThreadController, spStats, spSrcFileInfo, spLogFileData, spMemoryPool ? spMemoryPool->GetBufferList() : TBufferListPtr(), m_spRange, dwChunkSize, uiMaxConcurrentReads, uiMaxReadAhead, bNoBuffering, bProtectReadOnlyFiles)),
-		m_spWriter(std::make_shared<TOverlappedWriterFB>(spFilesystem, spFeedbackHandler, rThreadController, spStats, spSrcFileInfo, pathDst, spLogFileData, m_spReader->GetFinishedQueue(), m_spRange, spMemoryPool ? spMemoryPool->GetBufferList() : TBufferListPtr(), uiMaxConcurrentWrites, bOnlyCreate, bNoBuffering, bProtectReadOnlyFiles, bUpdateFileAttributesAndTimes))
+		m_spReader(std::make_shared<TOverlappedReaderFB>(spFilesystem, spFeedbackManager, rThreadController, spStats, spSrcFileInfo, spLogFileData, spMemoryPool ? spMemoryPool->GetBufferList() : TBufferListPtr(), m_spRange, dwChunkSize, uiMaxConcurrentReads, uiMaxReadAhead, bNoBuffering, bProtectReadOnlyFiles)),
+		m_spWriter(std::make_shared<TOverlappedWriterFB>(spFilesystem, spFeedbackManager, rThreadController, spStats, spSrcFileInfo, pathDst, spLogFileData, m_spReader->GetFinishedQueue(), m_spRange, spMemoryPool ? spMemoryPool->GetBufferList() : TBufferListPtr(), uiMaxConcurrentWrites, bOnlyCreate, bNoBuffering, bProtectReadOnlyFiles, bUpdateFileAttributesAndTimes))
 	{
 	}
 
Index: src/libchengine/TOverlappedReaderWriterFB.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TOverlappedReaderWriterFB.h	(.../TOverlappedReaderWriterFB.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TOverlappedReaderWriterFB.h	(.../TOverlappedReaderWriterFB.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -24,6 +24,7 @@
 #include "TOverlappedMemoryPool.h"
 #include "TOverlappedReaderFB.h"
 #include "TOverlappedWriterFB.h"
+#include "FeedbackManager.h"
 
 namespace chengine
 {
@@ -33,7 +34,7 @@
 	{
 	public:
 		explicit TOverlappedReaderWriterFB(const IFilesystemPtr& spFilesystem,
-			const IFeedbackHandlerPtr& spFeedbackHandler,
+			const FeedbackManagerPtr& spFeedbackManager,
 			TWorkerThreadController& rThreadController,
 			TOverlappedThreadPool& rThreadPool,
 			const TFileInfoPtr& spSrcFileInfo,
Index: src/libchengine/TOverlappedWriterFB.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TOverlappedWriterFB.cpp	(.../TOverlappedWriterFB.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TOverlappedWriterFB.cpp	(.../TOverlappedWriterFB.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -29,7 +29,7 @@
 namespace chengine
 {
 	TOverlappedWriterFB::TOverlappedWriterFB(const IFilesystemPtr& spFilesystem,
-		const IFeedbackHandlerPtr& spFeedbackHandler,
+		const FeedbackManagerPtr& spFeedbackManager,
 		TWorkerThreadController& rThreadController,
 		const TSubTaskStatsInfoPtr& spStats,
 		const TFileInfoPtr& spSrcFileInfo,
@@ -58,7 +58,7 @@
 	{
 		if(!spFilesystem)
 			throw TCoreException(eErr_InvalidArgument, L"spFilesystem is NULL", LOCATION);
-		if(!spFeedbackHandler)
+		if(!spFeedbackManager)
 			throw TCoreException(eErr_InvalidArgument, L"spFeedbackHandler is NULL", LOCATION);
 		if(!spStats)
 			throw TCoreException(eErr_InvalidArgument, L"spStats is NULL", LOCATION);
@@ -74,7 +74,7 @@
 			throw TCoreException(eErr_InvalidArgument, L"spBuffersToWrite is NULL", LOCATION);
 
 		IFilesystemFilePtr fileDst = spFilesystem->CreateFileObject(IFilesystemFile::eMode_Write, pathDst, bNoBuffering, bProtectReadOnlyFiles);
-		m_spDstFile = std::make_shared<TFilesystemFileFeedbackWrapper>(fileDst, spFeedbackHandler, spLogFileData, rThreadController, spFilesystem);
+		m_spDstFile = std::make_shared<TFilesystemFileFeedbackWrapper>(fileDst, spFeedbackManager, spLogFileData, rThreadController, spFilesystem);
 	}
 
 	TOverlappedWriterFB::~TOverlappedWriterFB()
Index: src/libchengine/TOverlappedWriterFB.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TOverlappedWriterFB.h	(.../TOverlappedWriterFB.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TOverlappedWriterFB.h	(.../TOverlappedWriterFB.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -33,7 +33,7 @@
 	{
 	public:
 		TOverlappedWriterFB(const IFilesystemPtr& spFilesystem,
-			const IFeedbackHandlerPtr& spFeedbackHandler,
+			const FeedbackManagerPtr& spFeedbackManager,
 		    TWorkerThreadController& rThreadController,
 			const TSubTaskStatsInfoPtr& spStats,
 			const TFileInfoPtr& spSrcFileInfo,
Index: src/libchengine/TScopedRunningTimeTrackerPause.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TScopedRunningTimeTrackerPause.cpp	(.../TScopedRunningTimeTrackerPause.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TScopedRunningTimeTrackerPause.cpp	(.../TScopedRunningTimeTrackerPause.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -23,13 +23,21 @@
 namespace chengine
 {
 	TScopedRunningTimeTrackerPause::TScopedRunningTimeTrackerPause(TScopedRunningTimeTracker& rRunningTimeTracker) :
-		m_rRunningTimeTracker(rRunningTimeTracker)
+		m_pRunningTimeTracker(&rRunningTimeTracker)
 	{
-		m_rRunningTimeTracker.PauseTimeTracking();
+		m_pRunningTimeTracker->PauseTimeTracking();
 	}
 
+	TScopedRunningTimeTrackerPause::TScopedRunningTimeTrackerPause(TScopedRunningTimeTracker* pRunningTimeTracker) :
+		m_pRunningTimeTracker(pRunningTimeTracker)
+	{
+		if(m_pRunningTimeTracker)
+			m_pRunningTimeTracker->PauseTimeTracking();
+	}
+
 	TScopedRunningTimeTrackerPause::~TScopedRunningTimeTrackerPause()
 	{
-		m_rRunningTimeTracker.UnPauseTimeTracking();
+		if(m_pRunningTimeTracker)
+			m_pRunningTimeTracker->UnPauseTimeTracking();
 	}
 }
Index: src/libchengine/TScopedRunningTimeTrackerPause.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TScopedRunningTimeTrackerPause.h	(.../TScopedRunningTimeTrackerPause.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TScopedRunningTimeTrackerPause.h	(.../TScopedRunningTimeTrackerPause.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -27,13 +27,14 @@
 	{
 	public:
 		explicit TScopedRunningTimeTrackerPause(TScopedRunningTimeTracker& rRunningTimeTracker);
+		explicit TScopedRunningTimeTrackerPause(TScopedRunningTimeTracker* pRunningTimeTracker);
 		~TScopedRunningTimeTrackerPause();
 
 		TScopedRunningTimeTrackerPause(const TScopedRunningTimeTrackerPause&) = delete;
 		TScopedRunningTimeTrackerPause& operator=(const TScopedRunningTimeTrackerPause&) = delete;
 
 	private:
-		TScopedRunningTimeTracker& m_rRunningTimeTracker;
+		TScopedRunningTimeTracker* m_pRunningTimeTracker;
 	};
 }
 
Index: src/libchengine/TSubTaskArray.cpp
===================================================================
diff -u -r9ddf8fdd5f641491dd30c49eb90f8f740314b6af -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskArray.cpp	(.../TSubTaskArray.cpp)	(revision 9ddf8fdd5f641491dd30c49eb90f8f740314b6af)
+++ src/libchengine/TSubTaskArray.cpp	(.../TSubTaskArray.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -154,7 +154,7 @@
 		}
 	}
 
-	TSubTaskBase::ESubOperationResult TSubTasksArray::Execute(const IFeedbackHandlerPtr& spFeedbackHandler, bool bRunOnlyEstimationSubTasks)
+	TSubTaskBase::ESubOperationResult TSubTasksArray::Execute(bool bRunOnlyEstimationSubTasks)
 	{
 		TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue;
 
@@ -175,7 +175,7 @@
 				break;
 			}
 
-			eResult = spCurrentSubTask->Exec(spFeedbackHandler);
+			eResult = spCurrentSubTask->Exec();
 			if (eResult != TSubTaskBase::eSubResult_Continue)
 				break;
 
Index: src/libchengine/TSubTaskArray.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskArray.h	(.../TSubTaskArray.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TSubTaskArray.h	(.../TSubTaskArray.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -59,7 +59,7 @@
 		void Load(const serializer::ISerializerPtr& spSerializer);
 
 		void InitBeforeExec();
-		TSubTaskBase::ESubOperationResult Execute(const IFeedbackHandlerPtr& spFeedbackHandler, bool bRunOnlyEstimationSubTasks);
+		TSubTaskBase::ESubOperationResult Execute(bool bRunOnlyEstimationSubTasks);
 
 		// checks if the fast move already marked all base paths as not be be further processed
 		bool AreAllBasePathsProcessed() const;
Index: src/libchengine/TSubTaskBase.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskBase.h	(.../TSubTaskBase.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TSubTaskBase.h	(.../TSubTaskBase.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -60,7 +60,7 @@
 		virtual void Reset() = 0;
 
 		virtual void InitBeforeExec() = 0;
-		virtual ESubOperationResult Exec(const IFeedbackHandlerPtr& spFeedbackHandler) = 0;
+		virtual ESubOperationResult Exec() = 0;
 		virtual ESubOperationType GetSubOperationType() const = 0;
 
 		// serialization
Index: src/libchengine/TSubTaskContext.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskContext.cpp	(.../TSubTaskContext.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TSubTaskContext.cpp	(.../TSubTaskContext.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -32,7 +32,7 @@
 	TSubTaskContext::TSubTaskContext(TConfig& rConfig, const TBasePathDataContainerPtr& spBasePaths,
 		const TFileFiltersArray& rFilters,
 		TTaskConfigTracker& rCfgTracker, const logger::TLogFileDataPtr& spLogFileData,
-		TWorkerThreadController& rThreadController, const IFilesystemPtr& spFilesystem) :
+		TWorkerThreadController& rThreadController, const IFilesystemPtr& spFilesystem, const FeedbackManagerPtr& spFeedbackManager) :
 		m_rConfig(rConfig),
 		m_eOperationType(eOperation_None),
 		m_spBasePaths(spBasePaths),
@@ -41,12 +41,15 @@
 		m_rCfgTracker(rCfgTracker),
 		m_spFilesystem(spFilesystem),
 		m_spLogFileData(spLogFileData),
-		m_rThreadController(rThreadController)
+		m_rThreadController(rThreadController),
+		m_spFeedbackManager(spFeedbackManager)
 	{
 		if (!spFilesystem)
 			throw TCoreException(eErr_InvalidArgument, L"spFilesystem", LOCATION);
-		if (!spLogFileData)
+		if(!spLogFileData)
 			throw TCoreException(eErr_InvalidArgument, L"spLogFileData", LOCATION);
+		if(!spFeedbackManager)
+			throw TCoreException(eErr_InvalidArgument, L"spFeedbackManager", LOCATION);
 	}
 
 	TSubTaskContext::~TSubTaskContext()
Index: src/libchengine/TSubTaskContext.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskContext.h	(.../TSubTaskContext.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TSubTaskContext.h	(.../TSubTaskContext.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -28,6 +28,8 @@
 #include "TFileInfoArray.h"
 #include "IFilesystem.h"
 #include "../liblogger/TLogFileData.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+#include "FeedbackManager.h"
 
 namespace chcore
 {
@@ -49,7 +51,8 @@
 		TSubTaskContext(TConfig& rConfig, const TBasePathDataContainerPtr& spBasePaths,
 			const TFileFiltersArray& rFilters,
 			TTaskConfigTracker& rCfgTracker, const logger::TLogFileDataPtr& spLogFileData,
-		                chcore::TWorkerThreadController& rThreadController, const IFilesystemPtr& spFilesystem);
+			chcore::TWorkerThreadController& rThreadController, const IFilesystemPtr& spFilesystem,
+			const FeedbackManagerPtr& spFeedbackManager);
 		TSubTaskContext(const TSubTaskContext& rSrc) = delete;
 		~TSubTaskContext();
 
@@ -64,6 +67,7 @@
 		TBasePathDataContainerPtr GetBasePaths() const;
 
 		const TFileFiltersArray& GetFilters() const;
+
 		TFileInfoArray& GetFilesCache();
 		const TFileInfoArray& GetFilesCache() const;
 
@@ -80,6 +84,9 @@
 
 		IFilesystemPtr GetLocalFilesystem() const;
 
+		FeedbackManagerPtr GetFeedbackManager() const { return m_spFeedbackManager; }
+		void SetFeedbackManager(const FeedbackManagerPtr& spFeedbackManager) { m_spFeedbackManager = spFeedbackManager; }
+
 	private:
 		TConfig& m_rConfig;
 
@@ -106,6 +113,8 @@
 #pragma warning(disable: 4251)
 		IFilesystemPtr m_spFilesystem;
 		logger::TLogFileDataPtr m_spLogFileData;
+
+		FeedbackManagerPtr m_spFeedbackManager;
 #pragma warning(pop)
 
 		// thread control
Index: src/libchengine/TSubTaskCopyMove.cpp
===================================================================
diff -u -r301444777085263aae7aff911dd56722f302597e -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskCopyMove.cpp	(.../TSubTaskCopyMove.cpp)	(revision 301444777085263aae7aff911dd56722f302597e)
+++ src/libchengine/TSubTaskCopyMove.cpp	(.../TSubTaskCopyMove.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -33,7 +33,6 @@
 #include "TFileInfo.h"
 #include "TFileInfoArray.h"
 #include "TScopedRunningTimeTracker.h"
-#include "TFeedbackHandlerWrapper.h"
 #include "TOverlappedMemoryPool.h"
 #include "TTaskConfigBufferSizes.h"
 #include "TFilesystemFeedbackWrapper.h"
@@ -42,6 +41,7 @@
 #include "TThreadedQueueRunner.h"
 #include "TOverlappedThreadPool.h"
 #include "../libchcore/RoundingFunctions.h"
+#include <boost/scope_exit.hpp>
 
 using namespace chcore;
 using namespace string;
@@ -98,11 +98,16 @@
 		m_spSubTaskStats->SetCurrentPath(spFileInfo->GetFullFilePath().ToString());
 	}
 
-	TSubTaskBase::ESubOperationResult TSubTaskCopyMove::Exec(const IFeedbackHandlerPtr& spFeedback)
+	TSubTaskBase::ESubOperationResult TSubTaskCopyMove::Exec()
 	{
 		TScopedRunningTimeTracker guard(*m_spSubTaskStats);
-		TFeedbackHandlerWrapperPtr spFeedbackHandler(std::make_shared<TFeedbackHandlerWrapper>(spFeedback, guard));
+		FeedbackManagerPtr spFeedbackManager = GetContext().GetFeedbackManager();
+		spFeedbackManager->SetSecondaryTimeTracker(&guard);
 
+		BOOST_SCOPE_EXIT(&spFeedbackManager) {
+			spFeedbackManager->SetSecondaryTimeTracker(nullptr);
+		} BOOST_SCOPE_EXIT_END
+
 		TFileInfoArray& rFilesCache = GetContext().GetFilesCache();
 		TTaskConfigTracker& rCfgTracker = GetContext().GetCfgTracker();
 		TWorkerThreadController& rThreadController = GetContext().GetThreadController();
@@ -111,7 +116,7 @@
 		IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem();
 		TBasePathDataContainerPtr spSrcPaths = GetContext().GetBasePaths();
 
-		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackHandler, spFilesystem, GetContext().GetLogFileData(), rThreadController);
+		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackManager, spFilesystem, GetContext().GetLogFileData(), rThreadController);
 
 		// log
 		LOG_INFO(m_spLog) << _T("Processing files/folders (ProcessFiles)");
@@ -230,7 +235,7 @@
 				ccp.spSrcFile = spFileInfo;
 
 				// copy data
-				eResult = CustomCopyFileFB(spFeedbackHandler, threadPool, &ccp);
+				eResult = CustomCopyFileFB(spFeedbackManager, threadPool, &ccp);
 				if (eResult == eSubResult_SkipFile)
 				{
 					spFileInfo->MarkAsProcessed(false);
@@ -338,7 +343,7 @@
 		}
 	}
 
-	TSubTaskBase::ESubOperationResult TSubTaskCopyMove::CustomCopyFileFB(const IFeedbackHandlerPtr& spFeedbackHandler,
+	TSubTaskBase::ESubOperationResult TSubTaskCopyMove::CustomCopyFileFB(const FeedbackManagerPtr& spFeedbackManager,
 		TOverlappedThreadPool& rThreadPool,
 		CUSTOM_COPY_PARAMS* pData)
 	{
@@ -368,7 +373,7 @@
 		unsigned long long ullNextReadPos = m_spSubTaskStats->GetCurrentItemProcessedSize();
 
 		TOverlappedReaderWriterFB tReaderWriter(spFilesystem,
-			spFeedbackHandler,
+			spFeedbackManager,
 			rThreadController,
 			rThreadPool,
 			pData->spSrcFile,
Index: src/libchengine/TSubTaskCopyMove.h
===================================================================
diff -u -r9ddf8fdd5f641491dd30c49eb90f8f740314b6af -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskCopyMove.h	(.../TSubTaskCopyMove.h)	(revision 9ddf8fdd5f641491dd30c49eb90f8f740314b6af)
+++ src/libchengine/TSubTaskCopyMove.h	(.../TSubTaskCopyMove.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -27,6 +27,7 @@
 #include "TBufferSizes.h"
 #include "../liblogger/TLogger.h"
 #include "TOverlappedMemoryPool.h"
+#include "FeedbackManager.h"
 
 namespace chengine
 {
@@ -46,7 +47,7 @@
 		void Reset() override;
 
 		void InitBeforeExec() override;
-		ESubOperationResult Exec(const IFeedbackHandlerPtr& spFeedbackHandler) override;
+		ESubOperationResult Exec() override;
 		ESubOperationType GetSubOperationType() const override { return eSubOperation_Copying; }
 
 		void Store(const serializer::ISerializerPtr& spSerializer) const override;
@@ -60,7 +61,7 @@
 		TBufferSizes::EBufferType GetBufferIndex(const TBufferSizes& rBufferSizes, const TFileInfoPtr& spFileInfo);
 		bool AdjustBufferIfNeeded(const TOverlappedMemoryPoolPtr& spBuffer, TBufferSizes& rBufferSizes, bool bForce = false);
 
-		ESubOperationResult CustomCopyFileFB(const IFeedbackHandlerPtr& spFeedbackHandler,
+		ESubOperationResult CustomCopyFileFB(const FeedbackManagerPtr& spFeedbackManager,
 			TOverlappedThreadPool& rThreadPool,
 			CUSTOM_COPY_PARAMS* pData);
 
Index: src/libchengine/TSubTaskDelete.cpp
===================================================================
diff -u -r06dcc90de4fac6573a68b147ad9d62b770042582 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskDelete.cpp	(.../TSubTaskDelete.cpp)	(revision 06dcc90de4fac6573a68b147ad9d62b770042582)
+++ src/libchengine/TSubTaskDelete.cpp	(.../TSubTaskDelete.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -31,9 +31,9 @@
 #include "TFileInfo.h"
 #include "TTaskLocalStats.h"
 #include "TScopedRunningTimeTracker.h"
-#include "TFeedbackHandlerWrapper.h"
 #include "TBufferSizes.h"
 #include "TFilesystemFeedbackWrapper.h"
+#include <boost/scope_exit.hpp>
 
 using namespace chcore;
 using namespace string;
@@ -75,17 +75,22 @@
 		m_tSubTaskStats.SetCurrentPath(spFileInfo->GetFullFilePath().ToString());
 	}
 
-	TSubTaskBase::ESubOperationResult TSubTaskDelete::Exec(const IFeedbackHandlerPtr& spFeedback)
+	TSubTaskBase::ESubOperationResult TSubTaskDelete::Exec()
 	{
 		TScopedRunningTimeTracker guard(m_tSubTaskStats);
-		TFeedbackHandlerWrapperPtr spFeedbackHandler(std::make_shared<TFeedbackHandlerWrapper>(spFeedback, guard));
+		FeedbackManagerPtr spFeedbackManager = GetContext().GetFeedbackManager();
+		spFeedbackManager->SetSecondaryTimeTracker(&guard);
 
+		BOOST_SCOPE_EXIT(&spFeedbackManager) {
+			spFeedbackManager->SetSecondaryTimeTracker(nullptr);
+		} BOOST_SCOPE_EXIT_END
+
 		// log
 		TFileInfoArray& rFilesCache = GetContext().GetFilesCache();
 		TWorkerThreadController& rThreadController = GetContext().GetThreadController();
 		IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem();
 
-		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackHandler, spFilesystem, GetContext().GetLogFileData(), rThreadController);
+		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackManager, spFilesystem, GetContext().GetLogFileData(), rThreadController);
 
 		// log
 		LOG_INFO(m_spLog) << _T("Deleting files (DeleteFiles)...");
Index: src/libchengine/TSubTaskDelete.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskDelete.h	(.../TSubTaskDelete.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TSubTaskDelete.h	(.../TSubTaskDelete.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -39,7 +39,7 @@
 		void Reset() override;
 
 		void InitBeforeExec() override;
-		ESubOperationResult Exec(const IFeedbackHandlerPtr& spFeedbackHandler) override;
+		ESubOperationResult Exec() override;
 		ESubOperationType GetSubOperationType() const override { return eSubOperation_Deleting; }
 
 		void Store(const serializer::ISerializerPtr& spSerializer) const override;
Index: src/libchengine/TSubTaskFastMove.cpp
===================================================================
diff -u -r9ddf8fdd5f641491dd30c49eb90f8f740314b6af -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskFastMove.cpp	(.../TSubTaskFastMove.cpp)	(revision 9ddf8fdd5f641491dd30c49eb90f8f740314b6af)
+++ src/libchengine/TSubTaskFastMove.cpp	(.../TSubTaskFastMove.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -31,10 +31,10 @@
 #include "TFileInfo.h"
 #include <boost/lexical_cast.hpp>
 #include "TScopedRunningTimeTracker.h"
-#include "TFeedbackHandlerWrapper.h"
 #include "TBufferSizes.h"
 #include "TFilesystemFeedbackWrapper.h"
 #include "TDestinationPathProvider.h"
+#include <boost/scope_exit.hpp>
 
 using namespace chcore;
 using namespace string;
@@ -77,11 +77,17 @@
 			m_tSubTaskStats.SetCurrentPath(TString());
 	}
 
-	TSubTaskFastMove::ESubOperationResult TSubTaskFastMove::Exec(const IFeedbackHandlerPtr& spFeedback)
+	TSubTaskFastMove::ESubOperationResult TSubTaskFastMove::Exec()
 	{
 		TScopedRunningTimeTracker guard(m_tSubTaskStats);
-		TFeedbackHandlerWrapperPtr spFeedbackHandler(std::make_shared<TFeedbackHandlerWrapper>(spFeedback, guard));
+		FeedbackManagerPtr spFeedbackManager = GetContext().GetFeedbackManager();
+		spFeedbackManager->SetSecondaryTimeTracker(&guard);
 
+		BOOST_SCOPE_EXIT(&spFeedbackManager) {
+			spFeedbackManager->SetSecondaryTimeTracker(nullptr);
+		} BOOST_SCOPE_EXIT_END
+
+
 		// log
 		TWorkerThreadController& rThreadController = GetContext().GetThreadController();
 		TBasePathDataContainerPtr spBasePaths = GetContext().GetBasePaths();
@@ -90,7 +96,7 @@
 		const TFileFiltersArray& rafFilters = GetContext().GetFilters();
 		IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem();
 
-		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackHandler, spFilesystem, GetContext().GetLogFileData(), rThreadController);
+		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackManager, spFilesystem, GetContext().GetLogFileData(), rThreadController);
 
 		LOG_INFO(m_spLog) << _T("Performing initial fast-move operation...");
 
Index: src/libchengine/TSubTaskFastMove.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskFastMove.h	(.../TSubTaskFastMove.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TSubTaskFastMove.h	(.../TSubTaskFastMove.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -42,7 +42,7 @@
 		void Reset() override;
 
 		void InitBeforeExec() override;
-		ESubOperationResult Exec(const IFeedbackHandlerPtr& spFeedbackHandler) override;
+		ESubOperationResult Exec() override;
 		ESubOperationType GetSubOperationType() const override { return eSubOperation_FastMove; }
 
 		void Store(const serializer::ISerializerPtr& spSerializer) const override;
Index: src/libchengine/TSubTaskScanDirectory.cpp
===================================================================
diff -u -r85b07e753393f661f7d8f528e4238ebb6e9e1204 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskScanDirectory.cpp	(.../TSubTaskScanDirectory.cpp)	(revision 85b07e753393f661f7d8f528e4238ebb6e9e1204)
+++ src/libchengine/TSubTaskScanDirectory.cpp	(.../TSubTaskScanDirectory.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -31,9 +31,9 @@
 #include "TFileInfoArray.h"
 #include "TFileInfo.h"
 #include "TScopedRunningTimeTracker.h"
-#include "TFeedbackHandlerWrapper.h"
 #include "TBufferSizes.h"
 #include "TFilesystemFeedbackWrapper.h"
+#include <boost/scope_exit.hpp>
 
 using namespace chcore;
 using namespace string;
@@ -78,11 +78,16 @@
 			m_tSubTaskStats.SetCurrentPath(TString());
 	}
 
-	TSubTaskScanDirectories::ESubOperationResult TSubTaskScanDirectories::Exec(const IFeedbackHandlerPtr& spFeedback)
+	TSubTaskScanDirectories::ESubOperationResult TSubTaskScanDirectories::Exec()
 	{
 		TScopedRunningTimeTracker guard(m_tSubTaskStats);
-		TFeedbackHandlerWrapperPtr spFeedbackHandler(std::make_shared<TFeedbackHandlerWrapper>(spFeedback, guard));
+		FeedbackManagerPtr spFeedbackManager = GetContext().GetFeedbackManager();
+		spFeedbackManager->SetSecondaryTimeTracker(&guard);
 
+		BOOST_SCOPE_EXIT(&spFeedbackManager) {
+			spFeedbackManager->SetSecondaryTimeTracker(nullptr);
+		} BOOST_SCOPE_EXIT_END
+
 		// log
 		TFileInfoArray& rFilesCache = GetContext().GetFilesCache();
 		TWorkerThreadController& rThreadController = GetContext().GetThreadController();
@@ -91,7 +96,7 @@
 		const TFileFiltersArray& rafFilters = GetContext().GetFilters();
 		IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem();
 
-		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackHandler, spFilesystem, GetContext().GetLogFileData(), rThreadController);
+		TFilesystemFeedbackWrapper tFilesystemFBWrapper(spFeedbackManager, spFilesystem, GetContext().GetLogFileData(), rThreadController);
 
 		LOG_INFO(m_spLog) << _T("Searching for files...");
 
Index: src/libchengine/TSubTaskScanDirectory.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TSubTaskScanDirectory.h	(.../TSubTaskScanDirectory.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TSubTaskScanDirectory.h	(.../TSubTaskScanDirectory.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -43,7 +43,7 @@
 		void Reset() override;
 
 		void InitBeforeExec() override;
-		ESubOperationResult Exec(const IFeedbackHandlerPtr& spFeedbackHandler) override;
+		ESubOperationResult Exec() override;
 		ESubOperationType GetSubOperationType() const override { return eSubOperation_Scanning; }
 
 		void Store(const serializer::ISerializerPtr& spSerializer) const override;
Index: src/libchengine/TTask.cpp
===================================================================
diff -u -rfa1b3554856407e4501db20d5093818e8d8c4068 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TTask.cpp	(.../TTask.cpp)	(revision fa1b3554856407e4501db20d5093818e8d8c4068)
+++ src/libchengine/TTask.cpp	(.../TTask.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -26,12 +26,12 @@
 #include "TTaskStatsSnapshot.h"
 #include "TScopedRunningTimeTracker.h"
 #include "TScopedRunningTimeTrackerPause.h"
-#include "TFeedbackHandlerWrapper.h"
 #include "TTaskConfigBufferSizes.h"
 #include <wchar.h>
 #include "TLocalFilesystem.h"
 #include "TTaskConfigVerifier.h"
 #include "../liblogger/TAsyncMultiLogger.h"
+#include <boost/scope_exit.hpp>
 
 using namespace chcore;
 using namespace string;
@@ -45,13 +45,12 @@
 	TTask::TTask(const ISerializerPtr& spSerializer, const IFeedbackHandlerPtr& spFeedbackHandler,
 		const TTaskDefinition& rTaskDefinition, const logger::TLogFileDataPtr& spLogFileData) :
 		m_spSerializer(spSerializer),
-		m_spInternalFeedbackHandler(spFeedbackHandler),
+		m_spFeedbackManager(std::make_shared<FeedbackManager>(spFeedbackHandler)),
 		m_spLog(logger::MakeLogger(spLogFileData, L"Task")),
 		m_spSrcPaths(new TBasePathDataContainer),
+		m_tSubTaskContext(m_tConfiguration, m_spSrcPaths, m_afFilters, m_cfgTracker, spLogFileData, m_workerThread, 
+			std::make_shared<TLocalFilesystem>(spLogFileData), m_spFeedbackManager),
 		m_tSubTasksArray(m_tSubTaskContext),
-		m_tSubTaskContext(m_tConfiguration, m_spSrcPaths, m_afFilters,
-		                  m_cfgTracker, spLogFileData, m_workerThread,
-		                  std::make_shared<TLocalFilesystem>(spLogFileData)),
 		m_bForce(false),
 		m_bContinue(false)
 	{
@@ -65,18 +64,15 @@
 
 	TTask::TTask(const ISerializerPtr& spSerializer, const IFeedbackHandlerPtr& spFeedbackHandler, const logger::TLogFileDataPtr& spLogFileData) :
 		m_spSerializer(spSerializer),
-		m_spInternalFeedbackHandler(spFeedbackHandler),
+		m_spFeedbackManager(std::make_shared<FeedbackManager>(spFeedbackHandler)),
 		m_spLog(logger::MakeLogger(spLogFileData, L"Task")),
 		m_spSrcPaths(new TBasePathDataContainer),
+		m_tSubTaskContext(m_tConfiguration, m_spSrcPaths, m_afFilters, m_cfgTracker, m_spLog->GetLogFileData(), m_workerThread,
+			std::make_shared<TLocalFilesystem>(m_spLog->GetLogFileData()), m_spFeedbackManager),
 		m_tSubTasksArray(m_tSubTaskContext),
-		m_tSubTaskContext(m_tConfiguration, m_spSrcPaths, m_afFilters,
-		                  m_cfgTracker, m_spLog->GetLogFileData(), m_workerThread,
-		                  std::make_shared<TLocalFilesystem>(m_spLog->GetLogFileData())),
 		m_bForce(false),
 		m_bContinue(false)
 	{
-		if(!spFeedbackHandler)
-			throw TCoreException(eErr_InvalidArgument, L"spFeedbackHandler", LOCATION);
 		if(!spSerializer)
 			throw TCoreException(eErr_InvalidArgument, L"spSerializer", LOCATION);
 	}
@@ -98,6 +94,7 @@
 		m_tConfiguration = rTaskDefinition.GetConfiguration();
 		*m_spSrcPaths = rTaskDefinition.GetSourcePaths();
 		m_afFilters = rTaskDefinition.GetFilters();
+		m_spFeedbackManager->SetRules(rTaskDefinition.GetFeedbackRules());
 		m_tBaseData.SetTaskName(rTaskDefinition.GetTaskName());
 
 		m_tSubTasksArray.Init(rTaskDefinition.GetOperationPlan());
@@ -170,12 +167,11 @@
 			spContainer = m_spSerializer->GetContainer(_T("filters"));
 			m_afFilters.Load(spContainer);
 
+			m_spFeedbackManager->Load(m_spSerializer);
+
 			spContainer = m_spSerializer->GetContainer(_T("local_stats"));
 			m_tLocalStats.Load(spContainer);
 
-			spContainer = m_spSerializer->GetContainer(_T("feedback"));
-			m_spInternalFeedbackHandler->Load(spContainer);
-
 			// ensure copy-based context entries are properly updated after loading
 			m_tSubTaskContext.SetDestinationPath(m_tBaseData.GetDestinationPath());
 			m_tSubTaskContext.SetOperationType(m_tSubTasksArray.GetOperationType());
@@ -274,12 +270,11 @@
 			spContainer = m_spSerializer->GetContainer(_T("filters"));
 			m_afFilters.Store(spContainer);
 
+			m_spFeedbackManager->Store(m_spSerializer);
+
 			spContainer = m_spSerializer->GetContainer(_T("local_stats"));
 			m_tLocalStats.Store(spContainer);
 
-			spContainer = m_spSerializer->GetContainer(_T("feedback"));
-			m_spInternalFeedbackHandler->Store(spContainer);
-
 			m_tSubTasksArray.Store(m_spSerializer);
 		}
 
@@ -349,7 +344,7 @@
 
 		SetTaskState(eTaskState_None);
 
-		m_spInternalFeedbackHandler->RestoreDefaults();
+		m_spFeedbackManager->RestoreDefaults();
 		m_tSubTasksArray.ResetProgressAndStats();
 		m_tLocalStats.Clear();
 		m_spSrcPaths->ResetProcessingFlags();
@@ -362,7 +357,7 @@
 
 	void TTask::RestoreFeedbackDefaults()
 	{
-		m_spInternalFeedbackHandler->RestoreDefaults();
+		m_spFeedbackManager->RestoreDefaults();
 	}
 
 	void TTask::PauseProcessing()
@@ -402,6 +397,7 @@
 		spSnapshot->SetThreadPriority(GetTaskPropValue<eTO_ThreadPriority>(m_tConfiguration));
 		spSnapshot->SetDestinationPath(m_tBaseData.GetDestinationPath().ToString());
 		spSnapshot->SetFilters(m_afFilters);
+		spSnapshot->SetFeedbackRules(m_spFeedbackManager->GetRules());
 		spSnapshot->SetTaskState(m_tBaseData.GetCurrentState());
 		spSnapshot->SetOperationType(m_tSubTasksArray.GetOperationType());
 
@@ -550,8 +546,14 @@
 	{
 		// start tracking time for this thread
 		TScopedRunningTimeTracker tProcessingGuard(m_tLocalStats);
-		TFeedbackHandlerWrapperPtr spFeedbackHandler(std::make_shared<TFeedbackHandlerWrapper>(m_spInternalFeedbackHandler, tProcessingGuard));
 
+		// set time tracker and ensure it is unset on scope exit
+		m_spFeedbackManager->SetTimeTracker(&tProcessingGuard);
+
+		BOOST_SCOPE_EXIT(&m_spFeedbackManager) {
+			m_spFeedbackManager->SetTimeTracker(nullptr);
+		} BOOST_SCOPE_EXIT_END
+
 		const size_t ExceptionBufferSize = 2048;
 		std::unique_ptr<wchar_t[]> upExceptionInfoBuffer(new wchar_t[ExceptionBufferSize]);
 		try
@@ -574,7 +576,7 @@
 			m_tSubTasksArray.InitBeforeExec();
 
 			// exec the estimation subtasks
-			TSubTaskBase::ESubOperationResult eResult = m_tSubTasksArray.Execute(spFeedbackHandler, true);
+			TSubTaskBase::ESubOperationResult eResult = m_tSubTasksArray.Execute(true);
 
 			// go into wait state only in case the preprocessing did not finish the operation already
 			// (only fast move can do that right now)
@@ -585,7 +587,7 @@
 				eResult = CheckForWaitState();	// operation limiting
 			}
 			if (eResult == TSubTaskBase::eSubResult_Continue)
-				eResult = m_tSubTasksArray.Execute(spFeedbackHandler, false);
+				eResult = m_tSubTasksArray.Execute(false);
 
 			// change status to finished
 			if (eResult == TSubTaskBase::eSubResult_Continue)
@@ -596,7 +598,7 @@
 			switch (eResult)
 			{
 			case TSubTaskBase::eSubResult_Error:
-				spFeedbackHandler->OperationError();
+				m_spFeedbackManager->OperationEvent(eOperationEvent_Error);
 				SetTaskState(eTaskState_Error);
 				break;
 
@@ -615,7 +617,7 @@
 				break;
 
 			case TSubTaskBase::eSubResult_Continue:
-				spFeedbackHandler->OperationFinished();
+				m_spFeedbackManager->OperationEvent(eOperationEvent_Finished);
 				SetTaskState(eTaskState_Finished);
 				break;
 
@@ -664,7 +666,7 @@
 		LOG_ERROR(m_spLog) << strMsg.c_str();
 
 		// let others know some error happened
-		spFeedbackHandler->OperationError();
+		m_spFeedbackManager->OperationEvent(eOperationEvent_Error);
 		SetTaskState(eTaskState_Error);
 
 		SetContinueFlag(false);
Index: src/libchengine/TTask.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TTask.h	(.../TTask.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TTask.h	(.../TTask.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -19,7 +19,6 @@
 #ifndef __TASK_H__
 #define __TASK_H__
 
-#include "IFeedbackHandler.h"
 #include "TTaskDefinition.h"
 #include "TTaskConfigTracker.h"
 #include "TBasePathData.h"
@@ -33,6 +32,7 @@
 #include "IFilesystem.h"
 #include "../liblogger/TLogger.h"
 #include "../libchcore/TWorkerThreadController.h"
+#include "FeedbackManager.h"
 
 namespace chengine
 {
@@ -136,7 +136,8 @@
 #pragma warning(disable: 4251)
 		serializer::ISerializerPtr m_spSerializer;
 		std::mutex m_mutexSerializer;
-		IFeedbackHandlerPtr m_spInternalFeedbackHandler;
+
+		FeedbackManagerPtr m_spFeedbackManager;
 #pragma warning(pop)
 
 		// base data
@@ -151,10 +152,9 @@
 		// Global task settings
 		TConfig m_tConfiguration;
 
+		TSubTaskContext m_tSubTaskContext;
 		TSubTasksArray m_tSubTasksArray;
 
-		TSubTaskContext m_tSubTaskContext;
-
 		TTaskConfigTracker m_cfgTracker;
 
 		// current task state (derivatives of the task initial information)
Index: src/libchengine/TTaskDefinition.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TTaskDefinition.cpp	(.../TTaskDefinition.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TTaskDefinition.cpp	(.../TTaskDefinition.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -173,6 +173,7 @@
 			throw TCoreException(eErr_MissingXmlData, L"Missing TaskDefinition.SourcePaths.Path", LOCATION);
 
 		GetConfigValue(rDataSrc, _T("TaskDefinition.Filters"), m_afFilters);
+		GetConfigValue(rDataSrc, _T("TaskDefinition.Feedback"), m_feedbackRules);
 
 		// destination path
 		if (!GetConfigValue(rDataSrc, _T("TaskDefinition.DestinationPath"), m_pathDestinationPath) || (!bAllowEmptyDstPath && m_pathDestinationPath.IsEmpty()))
@@ -251,10 +252,11 @@
 
 		SetConfigValue(rConfig, _T("TaskDefinition.Version"), m_ullTaskVersion);
 
+		SetConfigValue(rConfig, _T("TaskDefinition.Feedback"), m_feedbackRules);
+
 		rConfig.PutSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
 	}
 
-
 	const TFileFiltersArray& TTaskDefinition::GetFilters() const
 	{
 		return m_afFilters;
@@ -269,4 +271,19 @@
 	{
 		m_afFilters = rFilters;
 	}
+
+	const FeedbackRules& TTaskDefinition::GetFeedbackRules() const
+	{
+		return m_feedbackRules;
+	}
+
+	FeedbackRules& TTaskDefinition::GetFeedbackRules()
+	{
+		return m_feedbackRules;
+	}
+
+	void TTaskDefinition::SetFeedbackRules(const FeedbackRules& rFeedbackRules)
+	{
+		m_feedbackRules = rFeedbackRules;
+	}
 }
Index: src/libchengine/TTaskDefinition.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TTaskDefinition.h	(.../TTaskDefinition.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TTaskDefinition.h	(.../TTaskDefinition.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -27,6 +27,8 @@
 #include "TConfig.h"
 #include "TFileFiltersArray.h"
 #include "../libchcore/TPathContainer.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+#include "FeedbackRules.h"
 
 namespace chengine
 {
@@ -56,6 +58,11 @@
 		TFileFiltersArray& GetFilters();
 		void SetFilters(const TFileFiltersArray& rFilters);
 
+		// feedback rules
+		const FeedbackRules& GetFeedbackRules() const;
+		FeedbackRules& GetFeedbackRules();
+		void SetFeedbackRules(const FeedbackRules& rFeedbackRules);
+
 		// Destination path
 		void SetDestinationPath(const chcore::TSmartPath& pathDestination);
 		chcore::TSmartPath GetDestinationPath() const;
@@ -86,6 +93,7 @@
 		chcore::TPathContainer m_vSourcePaths;
 		chcore::TSmartPath m_pathDestinationPath;
 		TFileFiltersArray m_afFilters;
+		FeedbackRules m_feedbackRules;
 
 		TOperationPlan m_tOperationPlan;			///< Describes the operation along with sub-operations to be performed on the task input data
 
Index: src/libchengine/TTaskStatsSnapshot.cpp
===================================================================
diff -u -r9ddf8fdd5f641491dd30c49eb90f8f740314b6af -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TTaskStatsSnapshot.cpp	(.../TTaskStatsSnapshot.cpp)	(revision 9ddf8fdd5f641491dd30c49eb90f8f740314b6af)
+++ src/libchengine/TTaskStatsSnapshot.cpp	(.../TTaskStatsSnapshot.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -41,6 +41,7 @@
 		m_iThreadPriority(0),
 		m_strDestinationPath(),
 		m_filters(),
+		m_feedbackRules(),
 		m_eTaskState(eTaskState_None),
 		m_strTaskID(),
 		m_eOperationType(eOperation_None),
@@ -67,6 +68,7 @@
 		m_iThreadPriority = 0;
 		m_strDestinationPath.Clear();
 		m_filters.Clear();
+		m_feedbackRules.Clear();
 		m_eTaskState = eTaskState_None;
 		m_strTaskID.Clear();
 		m_eOperationType = eOperation_None;
Index: src/libchengine/TTaskStatsSnapshot.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/TTaskStatsSnapshot.h	(.../TTaskStatsSnapshot.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libchengine/TTaskStatsSnapshot.h	(.../TTaskStatsSnapshot.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -29,6 +29,8 @@
 #include "EOperationTypes.h"
 #include "ETaskCurrentState.h"
 #include "TaskID.h"
+#include "FeedbackAlreadyExistsRuleList.h"
+#include "FeedbackRules.h"
 
 namespace chengine
 {
@@ -79,6 +81,9 @@
 		const TFileFiltersArray& GetFilters() const { return m_filters; }
 		void SetFilters(const TFileFiltersArray& val) { m_filters = val; }
 
+		const FeedbackRules& GetFeedbackRules() const { return m_feedbackRules; }
+		void SetFeedbackRules(const FeedbackRules& val) { m_feedbackRules = val; }
+
 		ETaskCurrentState GetTaskState() const { return m_eTaskState; }
 		void SetTaskState(ETaskCurrentState val) { m_eTaskState = val; }
 
@@ -118,7 +123,11 @@
 
 		int m_iThreadPriority;
 		string::TString m_strDestinationPath;
+
 		TFileFiltersArray m_filters;
+
+		FeedbackRules m_feedbackRules;
+
 		ETaskCurrentState m_eTaskState;
 		string::TString m_strTaskID;
 		EOperationType m_eOperationType;
Index: src/libchengine/libchengine.vcxproj
===================================================================
diff -u -rf3c80778cfee0736195e00274c78040f7908ac5b -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/libchengine.vcxproj	(.../libchengine.vcxproj)	(revision f3c80778cfee0736195e00274c78040f7908ac5b)
+++ src/libchengine/libchengine.vcxproj	(.../libchengine.vcxproj)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -507,11 +507,20 @@
     <ClInclude Include="EFeedbackResult.h" />
     <ClInclude Include="EFileError.h" />
     <ClInclude Include="EngineConstants.h" />
+    <ClInclude Include="EOperationEvent.h" />
     <ClInclude Include="EOperationTypes.h" />
     <ClInclude Include="ESubTaskTypes.h" />
     <ClInclude Include="ETaskCurrentState.h" />
-    <ClInclude Include="FeedbackRule.h" />
-    <ClInclude Include="FeedbackRuleList.h" />
+    <ClInclude Include="FeedbackErrorRule.h" />
+    <ClInclude Include="FeedbackErrorRuleList.h" />
+    <ClInclude Include="FeedbackNotEnoughSpaceRule.h" />
+    <ClInclude Include="FeedbackNotEnoughSpaceRuleList.h" />
+    <ClInclude Include="FeedbackOperationEventRule.h" />
+    <ClInclude Include="FeedbackOperationEventRuleList.h" />
+    <ClInclude Include="FeedbackPredefinedRules.h" />
+    <ClInclude Include="FeedbackAlreadyExistsRule.h" />
+    <ClInclude Include="FeedbackAlreadyExistsRuleList.h" />
+    <ClInclude Include="FeedbackRules.h" />
     <ClInclude Include="IFeedbackHandler.h" />
     <ClInclude Include="IFeedbackHandlerFactory.h" />
     <ClInclude Include="IFilesystem.h" />
@@ -530,8 +539,7 @@
     <ClInclude Include="TEvent.h" />
     <ClInclude Include="TEventCounter.h" />
     <ClInclude Include="TEventGuard.h" />
-    <ClInclude Include="TFeedbackHandlerBase.h" />
-    <ClInclude Include="TFeedbackHandlerWrapper.h" />
+    <ClInclude Include="FeedbackManager.h" />
     <ClInclude Include="TFeedbackResult.h" />
     <ClInclude Include="TFilesystemFeedbackWrapper.h" />
     <ClInclude Include="TFileInfoFwd.h" />
@@ -615,8 +623,16 @@
     </ClCompile>
     <ClCompile Include="ConfigNode.cpp" />
     <ClCompile Include="ConfigNodeContainer.cpp" />
-    <ClCompile Include="FeedbackRule.cpp" />
-    <ClCompile Include="FeedbackRuleList.cpp" />
+    <ClCompile Include="FeedbackErrorRule.cpp" />
+    <ClCompile Include="FeedbackErrorRuleList.cpp" />
+    <ClCompile Include="FeedbackNotEnoughSpaceRule.cpp" />
+    <ClCompile Include="FeedbackNotEnoughSpaceRuleList.cpp" />
+    <ClCompile Include="FeedbackOperationEventRule.cpp" />
+    <ClCompile Include="FeedbackOperationEventRuleList.cpp" />
+    <ClCompile Include="FeedbackPredefinedRules.cpp" />
+    <ClCompile Include="FeedbackAlreadyExistsRule.cpp" />
+    <ClCompile Include="FeedbackAlreadyExistsRuleList.cpp" />
+    <ClCompile Include="FeedbackRules.cpp" />
     <ClCompile Include="IFeedbackHandler.cpp" />
     <ClCompile Include="IFeedbackHandlerFactory.cpp" />
     <ClCompile Include="IFilesystem.cpp" />
@@ -735,8 +751,7 @@
     <ClCompile Include="TEventGuard.cpp" />
     <ClCompile Include="TFeedbackResult.cpp" />
     <ClCompile Include="TFilesystemFeedbackWrapper.cpp" />
-    <ClCompile Include="TFeedbackHandlerBase.cpp" />
-    <ClCompile Include="TFeedbackHandlerWrapper.cpp" />
+    <ClCompile Include="FeedbackManager.cpp" />
     <ClCompile Include="TFilesystemFileFeedbackWrapper.cpp" />
     <ClCompile Include="TFileException.cpp" />
     <ClCompile Include="TLocalFilesystemFile.cpp" />
Index: src/libchengine/libchengine.vcxproj.filters
===================================================================
diff -u -rf3c80778cfee0736195e00274c78040f7908ac5b -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libchengine/libchengine.vcxproj.filters	(.../libchengine.vcxproj.filters)	(revision f3c80778cfee0736195e00274c78040f7908ac5b)
+++ src/libchengine/libchengine.vcxproj.filters	(.../libchengine.vcxproj.filters)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -96,6 +96,18 @@
     <Filter Include="Source Files\Filesystems\OverlappedIO\ThreadSupport">
       <UniqueIdentifier>{1412ea6d-b28c-4a96-b076-3094c476ce45}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Source Files\Feedback\AlreadyExists">
+      <UniqueIdentifier>{675e75c1-b53c-4cfa-baf0-73fd29efd52e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Feedback\Error">
+      <UniqueIdentifier>{3e00c6b6-92d8-4f97-8689-9df059db42f1}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Feedback\NotEnoughSpace">
+      <UniqueIdentifier>{19f5e9c0-f34a-482a-9f3c-f3eb712da553}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Feedback\OperationEvent">
+      <UniqueIdentifier>{4a4f6b0e-39cc-4228-a3ae-566d54464f05}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="ESubTaskTypes.h">
@@ -212,9 +224,6 @@
     <ClInclude Include="TTaskBaseData.h">
       <Filter>Source Files\Task</Filter>
     </ClInclude>
-    <ClInclude Include="TFeedbackHandlerWrapper.h">
-      <Filter>Source Files\Feedback</Filter>
-    </ClInclude>
     <ClInclude Include="TScopedRunningTimeTracker.h">
       <Filter>Source Files\Stats</Filter>
     </ClInclude>
@@ -224,9 +233,6 @@
     <ClInclude Include="IRunningTimeControl.h">
       <Filter>Source Files\Stats</Filter>
     </ClInclude>
-    <ClInclude Include="TFeedbackHandlerBase.h">
-      <Filter>Source Files\Feedback</Filter>
-    </ClInclude>
     <ClInclude Include="EFeedbackResult.h">
       <Filter>Source Files\Feedback</Filter>
     </ClInclude>
@@ -239,9 +245,6 @@
     <ClInclude Include="TTaskConfigBufferSizes.h">
       <Filter>Source Files\Task Config</Filter>
     </ClInclude>
-    <ClInclude Include="EFileError.h">
-      <Filter>Source Files\Feedback</Filter>
-    </ClInclude>
     <ClInclude Include="IFilesystem.h">
       <Filter>Source Files\Filesystems</Filter>
     </ClInclude>
@@ -381,15 +384,48 @@
     <ClInclude Include="TObsoleteFiles.h">
       <Filter>Source Files\Tools</Filter>
     </ClInclude>
-    <ClInclude Include="FeedbackRule.h">
+    <ClInclude Include="ECompareType.h">
+      <Filter>Source Files\Tools</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackPredefinedRules.h">
       <Filter>Source Files\Feedback</Filter>
     </ClInclude>
-    <ClInclude Include="FeedbackRuleList.h">
+    <ClInclude Include="FeedbackManager.h">
       <Filter>Source Files\Feedback</Filter>
     </ClInclude>
-    <ClInclude Include="ECompareType.h">
-      <Filter>Source Files\Tools</Filter>
+    <ClInclude Include="FeedbackAlreadyExistsRule.h">
+      <Filter>Source Files\Feedback\AlreadyExists</Filter>
     </ClInclude>
+    <ClInclude Include="FeedbackAlreadyExistsRuleList.h">
+      <Filter>Source Files\Feedback\AlreadyExists</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackErrorRule.h">
+      <Filter>Source Files\Feedback\Error</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackErrorRuleList.h">
+      <Filter>Source Files\Feedback\Error</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackNotEnoughSpaceRule.h">
+      <Filter>Source Files\Feedback\NotEnoughSpace</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackNotEnoughSpaceRuleList.h">
+      <Filter>Source Files\Feedback\NotEnoughSpace</Filter>
+    </ClInclude>
+    <ClInclude Include="EFileError.h">
+      <Filter>Source Files\Feedback\Error</Filter>
+    </ClInclude>
+    <ClInclude Include="EOperationEvent.h">
+      <Filter>Source Files\Feedback\OperationEvent</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackOperationEventRuleList.h">
+      <Filter>Source Files\Feedback\OperationEvent</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackOperationEventRule.h">
+      <Filter>Source Files\Feedback\OperationEvent</Filter>
+    </ClInclude>
+    <ClInclude Include="FeedbackRules.h">
+      <Filter>Source Files\Feedback</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="TSubTaskArray.cpp">
@@ -506,9 +542,6 @@
     <ClCompile Include="Tests\TestsTConfig.cpp">
       <Filter>Tests</Filter>
     </ClCompile>
-    <ClCompile Include="TFeedbackHandlerWrapper.cpp">
-      <Filter>Source Files\Feedback</Filter>
-    </ClCompile>
     <ClCompile Include="TScopedRunningTimeTracker.cpp">
       <Filter>Source Files\Stats</Filter>
     </ClCompile>
@@ -518,9 +551,6 @@
     <ClCompile Include="IRunningTimeControl.cpp">
       <Filter>Source Files\Stats</Filter>
     </ClCompile>
-    <ClCompile Include="TFeedbackHandlerBase.cpp">
-      <Filter>Source Files\Feedback</Filter>
-    </ClCompile>
     <ClCompile Include="TTaskConfigTracker.cpp">
       <Filter>Source Files\Task Config</Filter>
     </ClCompile>
@@ -668,12 +698,39 @@
     <ClCompile Include="TObsoleteFiles.cpp">
       <Filter>Source Files\Tools</Filter>
     </ClCompile>
-    <ClCompile Include="FeedbackRule.cpp">
+    <ClCompile Include="FeedbackPredefinedRules.cpp">
       <Filter>Source Files\Feedback</Filter>
     </ClCompile>
-    <ClCompile Include="FeedbackRuleList.cpp">
+    <ClCompile Include="FeedbackManager.cpp">
       <Filter>Source Files\Feedback</Filter>
     </ClCompile>
+    <ClCompile Include="FeedbackAlreadyExistsRule.cpp">
+      <Filter>Source Files\Feedback\AlreadyExists</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackAlreadyExistsRuleList.cpp">
+      <Filter>Source Files\Feedback\AlreadyExists</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackErrorRuleList.cpp">
+      <Filter>Source Files\Feedback\Error</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackErrorRule.cpp">
+      <Filter>Source Files\Feedback\Error</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackNotEnoughSpaceRuleList.cpp">
+      <Filter>Source Files\Feedback\NotEnoughSpace</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackNotEnoughSpaceRule.cpp">
+      <Filter>Source Files\Feedback\NotEnoughSpace</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackOperationEventRuleList.cpp">
+      <Filter>Source Files\Feedback\OperationEvent</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackOperationEventRule.cpp">
+      <Filter>Source Files\Feedback\OperationEvent</Filter>
+    </ClCompile>
+    <ClCompile Include="FeedbackRules.cpp">
+      <Filter>Source Files\Feedback</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="libchengine.rc">
Index: src/libserializer/SerializableContainer.h
===================================================================
diff -u -rf3c80778cfee0736195e00274c78040f7908ac5b -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libserializer/SerializableContainer.h	(.../SerializableContainer.h)	(revision f3c80778cfee0736195e00274c78040f7908ac5b)
+++ src/libserializer/SerializableContainer.h	(.../SerializableContainer.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -62,6 +62,18 @@
 			return false;
 		}
 
+		bool InsertAt(size_t stIndex, const T& rNewEntry)
+		{
+			BOOST_ASSERT(stIndex <= m_vEntries.size());
+			if(stIndex <= m_vEntries.size())
+			{
+				m_vEntries.insert(m_vEntries.begin() + stIndex, rNewEntry);
+				return true;
+			}
+
+			return false;
+		}
+
 		const T& GetAt(size_t stIndex) const
 		{
 			if(stIndex >= m_vEntries.size())
@@ -70,6 +82,14 @@
 			return m_vEntries.at(stIndex);
 		}
 
+		T& GetAt(size_t stIndex)
+		{
+			if(stIndex >= m_vEntries.size())
+				throw std::out_of_range("stIndex is out of range");
+
+			return m_vEntries.at(stIndex);
+		}
+
 		bool RemoveAt(size_t stIndex)
 		{
 			BOOST_ASSERT(stIndex < m_vEntries.size());
Index: src/libserializer/TSQLiteTaskSchema.cpp
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libserializer/TSQLiteTaskSchema.cpp	(.../TSQLiteTaskSchema.cpp)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libserializer/TSQLiteTaskSchema.cpp	(.../TSQLiteTaskSchema.cpp)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -62,6 +62,9 @@
 
 			if(tVersion.GetVersion() == 5)
 				Migrate_005_006(spDatabase, tVersion);
+				
+			if(tVersion.GetVersion() == 6)
+				Migrate_006_007(spDatabase, tVersion);
 		}
 
 		tTransaction.Commit();
@@ -125,8 +128,15 @@
 		tStatement.Prepare(_T("CREATE TABLE feedback(id BIGINT UNIQUE, file_error INT NOT NULL, file_already_exists INT NOT NULL, not_enough_space INT NOT NULL, operation_finished INT NOT NULL, operation_error INT NOT NULL)"));
 		tStatement.Step();
 
+		tStatement.Prepare(_T("CREATE TABLE feedback_already_exists(id BIGINT UNIQUE, use_mask INT NOT NULL, mask varchar(32768) NOT NULL, ")
+			_T("use_exclude_mask INT NOT NULL, exclude_mask varchar(32768) NOT NULL, ")
+			_T("use_date_compare INT NOT NULL, date_compare_type INT NOT NULL, ")
+			_T("use_size_compare INT NOT NULL, size_compare_type INT NOT NULL, ")
+			_T("result INT NOT NULL)"));
+		tStatement.Step();
+
 		// and finally set the database version to current one
-		tVersion.SetVersion(5);
+		tVersion.SetVersion(7);
 	}
 
 	void TSQLiteTaskSchema::Migrate_001_002(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion &tVersion)
@@ -258,4 +268,23 @@
 
 		tVersion.SetVersion(6);
 	}
+
+	void TSQLiteTaskSchema::Migrate_006_007(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion& tVersion)
+	{
+		sqlite::TSQLiteStatement tStatement(spDatabase);
+
+		// remove old feedback table (with no migration)
+// 		tStatement.Prepare(_T("DROP TABLE feedback"));
+// 		tStatement.Step();
+
+		// create new feedback tables
+		tStatement.Prepare(_T("CREATE TABLE feedback_already_exists(id BIGINT UNIQUE, use_mask INT NOT NULL, mask varchar(32768) NOT NULL, ")
+			_T("use_exclude_mask INT NOT NULL, exclude_mask varchar(32768) NOT NULL, ")
+			_T("use_date_compare INT NOT NULL, date_compare_type INT NOT NULL, ")
+			_T("use_size_compare INT NOT NULL, size_compare_type INT NOT NULL, ")
+			_T("result INT NOT NULL)"));
+		tStatement.Step();
+
+		tVersion.SetVersion(7);
+	}
 }
Index: src/libserializer/TSQLiteTaskSchema.h
===================================================================
diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r08717141ce5f6926116c298cbc9442094a45bb67
--- src/libserializer/TSQLiteTaskSchema.h	(.../TSQLiteTaskSchema.h)	(revision 0d5b67ee96b435d63f7bf075dc8e28603793b187)
+++ src/libserializer/TSQLiteTaskSchema.h	(.../TSQLiteTaskSchema.h)	(revision 08717141ce5f6926116c298cbc9442094a45bb67)
@@ -40,7 +40,8 @@
 		void Migrate_002_003(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion &tVersion);
 		void Migrate_003_004(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion &tVersion);
 		void Migrate_004_005(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion &tVersion);
-		void Migrate_005_006(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion &tVersion);
+		void Migrate_005_006(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion& tVersion);
+		void Migrate_006_007(const sqlite::TSQLiteDatabasePtr& spDatabase, TSerializerVersion& tVersion);
 	};
 
 	typedef std::shared_ptr<TSQLiteTaskSchema> TSQLiteTaskSchemaPtr;