-- svn version:7.0.0.43 2011.05.16 修改扫描清理Real Player历史记录时，会误扫误删非lnk类型文件
-- svn version:7.0.0.42 2011.05.10 修改清不掉IE历史记录
-- svn version:7.0.0.40 2011.05.10 修改RealPlayer无法删除注册表
-- svn version:7.0.0.39 2011.05.05 修改无法扫描autosave.win文件、误删非.lnk文件、firefox重复清空、RealPlayer扫描清理功能无效
-- svn version:7.0.0.36 2011.03.08 修改 暴风影音，Kugoo 项清除错误的问题
-- svn version:7.0.0.35 2011.02.25 根据更新的文档修改 firefox.history 的操作内容
-- svn version:7.0.0.34 2011.02.17 根据更新的文档修改windowslive toolbar, 7-zip, maxthon, realplayer 的操作内容
-- svn version:7.0.0.34 2011.02.17 根据更新的文档修改windowslive toolbar, 7-zip, maxthon, realplayer 的操作内容
-- svn version:7.0.0.33 2011.01.21 修改getenv的结果的判断，ie 历史纪录不再删除desktop.ini
-- svn version:7.0.0.32 2011.01.20 修改xml关于node和attribute操作的细节
-- svn version:7.0.0.31 2011.01.19 加public
-- svn version:7.0.0.30 2011.01.19 修改把写错的提上去
-- svn version:7.0.0.29 2011.01.18 风暴影音修改
-- svn version:7.0.0.28 旺旺的获取位置没有去掉文件名称
-- svn version:7.0.0.27 书写错误导致找不到
-- svn version:7.0.0.26 Web Data,书写错误导致找不到
-- svn version:7.0.0.25 修改了因为误操作导致的文件扩展名清理时长时间不退出的问题


-- ************************************************************
-- Test Support Part
-- ************************************************************
--[[
function _GetSpecialFolder( s )
	if s == 40 then
		return "c:\\Documents and Settings\\Ji Wang"
	elseif s == 35 then
		return "c:\\Documents and Settings\\All Users\\Application Data"
	elseif s == 33 then
		return "C:\\Documents and Settings\\Ji Wang\\Cookies"
	end
end

function _ReturnFalse (s)
	return false
end

function _ReturnSize(s)
	print( string.format("\t\t\t\t_ReturnSize : %s", tostring(s)) )
	return 7
end

function _ReturnHresult(s)
	print( string.format("\t\t\t\t_ReturnHresult : %s", tostring(s)) )
	return 5
end

function _ReturnHandle(s)
	print( string.format("\t\t\t\t_ReturnHandle : %s", tostring(s)) )
	return 10
end

function _ReturnString(s)
	print( string.format( "\t\t\t\tReturnString : %s", tostring(s)) )
	return tostring(i)
end

function _ReturnEnumHandle(s, i)
	print( string.format( "\t\t\t\t_ReturnEnumHandle : %s", tostring(s)) )
	return 10;
end

function _ReturnEnumString(s, i)
	print( string.format( "\t\t\t\t_ReturnEnumString : %s", tostring(s)) )
	return "enum string";
end

function CFile ()
	return { GetSpecialFolder	= _GetSpecialFolder,
			  ReturnFalse		= _ReturnFalse
			}
end

function CRegHandle ()
	return {OpenKey			= _ReturnHandle,
			 CloseKey			= _ReturnHresult,
			 EnumSubKey   		= _ReturnEnumHandle,
			 OpenSubKey			= _ReturnHresult,
			 EnumSubKeyName		= _ReturnEnumString,
			 GetValue  			= _ReturnString,
			 EnumValueName		= _ReturnEnumString,
			 GetSubKeyCount		= _ReturnSize,
			 GetValueCount		= _ReturnSize,
			 DelValue			= _ReturnHresult,
			 DelKey				= _ReturnHresult,
			 ClearKey			= _ReturnSize
		    }
end

function CFileGroup()
	return { AssignFolder		= _ReturnHresult,
			  DeleteFiles		= _ReturnHresult,
			  CountFile			= _ReturnSize,
			  GetFileSize		= _ReturnSize,
			  GetSize			= _ReturnSize,
			  Exclude			= _ReturnHresult,
			  DelFile			= _ReturnHresult
			}
end


function CRecycle ()
	return {Query				= _ReturnHresult,
			 Size				= _ReturnSize,
			 Count				= _ReturnSize
			}
end

function CXml()
	return {DelPath			= _ReturnHresult,
			 Commit				= _ReturnHresult,
			 Open				= _ReturnHresult
			}
end

--]]
-- ************************************************************
-- Entry
-- ************************************************************

Actions = {}		-- new action array


-- debug
function DebugOutput( info )
	local f = io.open("c:\\1.txt", "a")
	f:write( tostring(info).."\n" )
	f:close()
end
-- debug


function Invoke ( id )
	if Actions[id] == nil then
		table.insert( lasterror, string.format( "id[%s] does not exist", tostring(id) ) )
		success, failed = 0, 1
	else
		TrackReset()
		Actions[id]()
	end
	local result = string.format( "count=%d,failed=%d,size=%d,error=%s",success, failed, filesize, GetLastError() )
--	DebugOutput( tostring(id)..":\n\t"..result)
	return result
end


-- ************************************************************
-- Helper Functions
-- ************************************************************
function Initialize( clean )
	lasterror  = {}
	success	   = 0
	failed     = 0
	filesize   = 0
	isclean	   = clean

	fileobj    = CFile()
	regobj 	   = CRegHandle()

	syspath = {}
	for k,i in pairs({ profile=40, cookies=33, common_appdata=35, local_appdata=28, profile_appdata=26 }) do
		syspath[k] = fileobj.GetSpecialFolder(i).c_str()
		if VerifyString(syspath[k]) == false then
			table.insert( lasterror, string.format("failed to get special folder path[%d]", i) )
			return false
		end
	end
	return true
end


function TrackReset()
	lasterror = {}
	success   = 0
	failed    = 0
	filesize  = 0
end


function TrackOp( exp, Verify, err )
	if Verify( exp ) == false then
		table.insert( lasterror, tostring(err) )
		failed  = failed  + 1
	else
		-- debug
		-- table.insert( lasterror, "succeed : "..tostring(err) )
		-- debug
		success = success + tonumber(exp)
	end
end


function VerifyResult( s )
	return s ~= nil and tonumber(s) > 0
end


function VerifyString( s )
	return (s ~= nil) and ( tostring(s) ~= tostring(nil) ) and (tostring(s) ~= "")
end


function GetLastError()
	return table.concat(lasterror, "\n")
end

-- ************************************************************
-- Composite Functions Wrapper
-- ************************************************************

-- 删除给定目录下的所有文件和子目录
function CleanDirWrap ( dirpath, pattern, excludes )
	local dir  = CFileGroup()
	local path = tostring(dirpath)

	if VerifyString(pattern) == false then
		dir.AssignFolder( path, "*.*" )
	else
		dir.AssignFolder( path, pattern )
	end

	if excludes ~= nil then
		for k, i in pairs(excludes) do
			dir.Exclude( i )
		end
	end

	filesize = dir.GetFolderSize()  + filesize
	if isclean == true then
		TrackOp( dir.DeleteFiles(), VerifyResult, 	string.format("CleanDir failed with [%s]", path) )
		filesize  = filesize - dir.GetFolderSize()
	else
		TrackOp( dir.CountFile(),	VerifyResult, 	string.format("CleanDir(scan mode) faield with [%s]", path) )
	end
end


-- 删除给定目录下的指定格式的文件及子目录文件
function CleanSpecDirWrap(dirpath, pattern, excludes)
	local dir = CFileGroup()
	local path = tostring(dirpath)

	if VerifyString(pattern) == true then
		dir.AssignFolder(path, pattern)
	end

	if excludes ~= nil then
		for k, i in pairs(excludes) do
			dir.Exclude(i)
		end
	end

	filesize = dir.GetFolderSize() + filesize
	if isclean == true then
		TrackOp( dir.DeleteSpecFiles(pattern), VerifyResult, 	string.format("CleanDir failed with [%s]", path) )
		filesize  = filesize - dir.GetFolderSize()
	else
		TrackOp( dir.CountSpecFile(pattern),	VerifyResult, 	string.format("CleanDir(scan mode) faield with [%s]", path) )
	end
end



-- 删除文件
function DeleteFileWrap (filepath)
	print("DeleteFileWarp:" .. filepath)
	local dir  = CFileGroup()
	local path = tostring(filepath)

	local s = success
	local n = dir.GetFileSize( path )		-- 获取大小失败时会返回-1，这个值可以认为是该文件不存在

	if isclean == true then
		TrackOp( dir.DelFile(path), VerifyResult,  string.format("DelFile failed with [%s]", path) )
	else
		if n >= 0 then		-- 只要不为-1就可以认为文件是存在的，所以返回文件计数应该为1
			TrackOp(1, 	VerifyResult,  string.format("DelFile(scan mode) failed with [%s]", path) )
		else
			TrackOp(0, 	VerifyResult,  string.format("DelFile(scan mode) failed with [%s]", path) )
		end
	end

	if s < success then
		filesize = filesize  + n
	end
end


-- 清除IE的历史记录
function CleanIEHistroy()
	local dir = CFileGroup()

	if isclean == true then
		dir.IECleanHistory()
	end
end


-- 删除给定键的指定子键下的所有键值和子键, 但保留当前子键
function ClearSubKeyWrap ( handle, subkeypath )
    local path = tostring(subkeypath)
	local h    = regobj.OpenSubKey( handle, path )

	if isclean == true then
		TrackOp( regobj.ClearKey(h), VerifyResult, string.format("ClearSubKey failed with [%s]", path) )
	else
		TrackOp( regobj.CountRegHandle(h), 	VerifyResult, string.format("ClearSubKey(scan mode) failed with [%s]", path) )
	end
	regobj.CloseKey(h)
end


-- 删除指定键下的指定子键
function DeleteSubKeyWrap( handle, subkeyname )
	local name = tostring(subkeyname)

	if isclean == true then
		TrackOp( regobj.DelKey(handle, name), VerifyResult, string.format("DeleteSubKey failed with [%s]", name) )
	else
		local k = regobj.OpenSubKey( handle, name )
		if VerifyResult( k ) == true then
			TrackOp( 1, 	VerifyResult, string.format("DeleteSubKey(scan mode) failed with [%s]", name) )
		else
			TrackOp( 0, 	VerifyResult, string.format("DeleteSubKey(scan mode) failed with [%s]", name) )
		end
		regobj.CloseKey(k)
	end
end


-- 删除指定键下的所有子键和键值，但保留保留当前键
function ClearKeyWrap ( keypath )
    local path =  tostring(keypath)
	local h    =  regobj.OpenKey(path)

	if isclean == true then
		TrackOp( regobj.ClearKey(h),	 	VerifyResult, string.format("ClearKey failed with [%s]", path ) )
	else
		TrackOp( regobj.CountRegHandle(h),	VerifyResult, string.format("ClearKey(scan mode) failed with [%s]", path) )
	end
	regobj.CloseKey(h)
end


-- 删除指定键的指定键值
function DeleteValueWrap ( handle, valuename )
    local name = tostring(valuename)

	if isclean == true then
		TrackOp( regobj.DelValue(handle, name), VerifyResult, string.format("DeleteValue failed with [%s]", name) )
	else
		print(handle, name, regobj.IsValidValue(handle, name))
		TrackOp( regobj.IsValidValue(handle, name), VerifyResult, string.format("DeleteValue(scan mode) failed with [%s]", name) )
	end
end


-- 清除回收站里面的所有文件
function EmptyRecycleWrap()
	local cobj = CRecycle()
	cobj.Query()
	local n = cobj.Size()
	local nCount = cobj.Count()
	filesize  = filesize  + n
	if isclean == true then
		if VerifyResult( cobj.Empty() ) == true then
			cobj.Query()
			local nCur = cobj.Count()
			TrackOp( nCount - nCur, VerifyResult, "EmptyRecycle failed" )
		else
			TrackOp( 0, VerifyResult, "EmptyRecycle failed" )
		end
		filesize  = filesize  - cobj.Size()
	else
		TrackOp( cobj.Count(), VerifyResult, "EmptyRecycle(scan mode) failed" )
	end
end


-- 清除剪贴板
function ClearClipWrap()
	local cobj = CClipBoard()

	if isclean == true then
		local nRet = cobj.Clear()
		local nCount = cobj.Count()
		TrackOp( nRet,  VerifyResult, string.format("EmptyClipboard:%d %d",nCount, nRet) )
	else
		-- alway clean clipboard
		TrackOp( 0,		     			 VerifyResult, string.format("EmptyClipboard(scan mode) failed") )
	end
end


-- 删除指定xml文件中的指定节点的指定属性
function DeleteXmlNodeAttributeWrap( filepath, nodename, nodepath, attrname )
	local xmlobj 	= CXml()
	local file   	= tostring(filepath)
	local path		= tostring(nodepath)
	local node   	= tostring(nodename)
	local attr   	= tostring(attrname)

	if VerifyResult( xmlobj.Open( file ) ) == false then return end

	local nodelist = xmlobj.FindNodeHandle(node, "")
	for i = 0, nodelist.size() - 1, 1 do
		local h = nodelist.at(i)
		if tostring( xmlobj.GetNodePath(h) ) == path then
			if isclean == true then
				TrackOp( xmlobj.DelAttByHandle(h, attr),		VerifyResult, string.format("DeleteXmlNodeAttribute failed with [%s, %s : %s : %s]", file, path, node, attr) )
			else
				local s = 0
				if ( VerifyString( xmlobj.GetAttributeByHandle(h, attr) ) == true ) then s = 1 end
				TrackOp( s, VerifyResult, string.format("DeleteXmlNodeAttribute(scan mode) failed with [%s, %s : %s : %s]", file, path, node, attr) )
			end
		end
	end
	xmlobj.Commit()
end


-- 删除指定xml path的节点
function DeleteXmlNodeWrap(filepath, nodename, nodepath)
	local xmlobj 	= CXml()
	local file   	= tostring(filepath)
	local node   	= tostring(nodename)
	local path		= tostring(nodepath)

	if VerifyResult( xmlobj.Open( file ) ) == false then return end

	local nodelist = xmlobj.FindNodeHandle(node, "")
	for i = 0, nodelist.size() - 1, 1 do
		local h = nodelist.at(i)
		if tostring( xmlobj.GetNodePath(h) ) == path then
			if isclean == true then
				TrackOp( xmlobj.DelNodeByHandle(h),		VerifyResult, string.format("DeleteXmlNode failed with [%s : %s : %s]", file, path, node) )
			else
				TrackOp( 1, 							VerifyResult, string.format("DeleteXmlNode(scan mode) failed with [%s : %s : %s]", file, path, node) )
			end
		end
	end
	xmlobj.Commit()
end


-- 删除给定数据库中的指定表
function CleanTableWrap(filepath, tablename)
	local splitobj = CDB()
	local path = tostring(filepath)
	local name = tostring(tablename)

	splitobj.OpenDB(path)

	if splitobj.CountRow(name) <= 0 then
		splitobj.CloseDB()
		return
	end

	if isclean == true then
		TrackOp(splitobj.ClearTable(name), 	VerifyResult, string.format("ClearTable failed with [%s : %s]", path, name) )
	else
		TrackOp(1, 	VerifyResult, string.format("ClearTable(scan mode) failed with [%s : %s]", path, name) )
	end
	splitobj.CloseDB()
end


function ClearCacheWrap(arg)
	local cacheobj = CCacheEntry()
	local sIEVersionHandle = regobj.OpenKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Internet Explorer");

	local sIEVer = regobj.GetValue(sIEVersionHandle, "Version")
	print("IE Version:", sIEVer)

	local nCondition = 0 -- 0 for ie 6, 1 for upper ie6

	if tonumber(string.sub(sIEVer.c_str(),1,1)) >= 7 then
		nCondition = 1
	end

	print("Condition:", nCondition)

	if isclean == true then
		TrackOp( cacheobj.Shdocvw211(arg, nCondition), VerifyResult, string.format("Clear Cache failed") )
		if nCondition == 0 then
			TrackOp( cacheobj.Shdocvw164(0, nCondition), VerifyResult, string.format("Clear Cache failed") )
		end
	else
		TrackOp( 1,		 VerifyResult, string.format("Clear Cache(scan mode) failed") )
		if nCondition == 0 then
			TrackOp( 1, 	 VerifyResult, string.format("Clear Cache(scan mode) failed") )
		end
	end
end


-- 清除给定ini文件中的给定itemlist下的所有items
function CleanINIItem(filepath, itemcategory, patterns)
    local path 		= tostring(filepath)
	local category	= tostring(itemcategory)

	local content 	= {}
	local header	= ""

	local f = io.open(path, "r")
	if f == nil then
		TrackOp(-1, VerifyResult, string.format("Failed to find config file : %s", path) )
	else
		local l = 0
		for line in f:lines() do
			local recode = false
			if true == isclean then recode = true end

            local h, e = string.find(line, "%[.*%]")
			if h ~= nil then
				header = string.sub(line, h + 1, e - 1)
			else
				if (header == category) then
					for k, i in pairs(patterns) do
						if string.find(line, "^"..i) ~= nil then
							l = l + 1
							if true == isclean then recode = false end
							break
						end
					end
				end
			end

			if true == recode then	table.insert(content, line)	end
		end
		f:close()

		if true == isclean then
			f = io.open(path, "w")
			f:write(table.concat(content,"\n") )
			f:close()
		end

		TrackOp(l,  VerifyResult, string.format("Failed to find config file : %s", path) )
	end
end


-- ************************************************************
-- Part I : Browser Cookie
-- ************************************************************

Actions['ie.cookie'] = function ()
	CleanDirWrap( syspath["cookies"], "*.*", {"index.dat"} )
end

Actions['chrome.cookie'] = function ()
	DeleteFileWrap(syspath["local_appdata"].."\\Google\\Chrome\\User Data\\Default\\Cookies")
end

Actions['sogou.cookie'] = function ()
	CleanDirWrap( syspath["profile_appdata"].."\\SogouExplorer\\WebKit\\Cookies" ,"*.*" )	
end

Actions['firefox.cookie'] = function ()
	CleanDirWrap( syspath["profile_appdata"].."\\Mozilla\Firefox\\%DataFile1%" ,"*.*" )	
end

Actions['maxthon.cookie'] = function ()
	DeleteFileWrap(syspath["profile_appdata"].."\\Maxthon3\\Users\\guest\\Cookie\\Cookie.dat")
end

Actions['360safe.cookie'] = function ()
	CleanDirWrap(syspath["profile_appdata"].."\\360se6\\User Data\\Default\\Cookies" ,"*.*" )
end

Actions['360extreme.cookie'] = function ()
	CleanDirWrap( syspath["local_appdata"].."\\360Chrome\\Chrome\\User Data\\Default" ,"*.*" )	
end

Actions['liebao.cookie'] = function ()
	CleanDirWrap( syspath["local_appdata"].."\\liebao\\User Data\\Default\\Cookies" ,"*.*" )	
end

Actions['qq.cookie'] = function ()
	CleanDirWrap( syspath["profile_appdata"].."\\Tencent\\QQBrowser\\webkit_cache" ,"*.*" )	
	CleanDirWrap( syspath["profile_appdata"].."\\Tencent\\QQBrowser\\user_data\\0" ,"*.*" )	
end

Actions['baidu.cookie'] = function ()
	DeleteFileWrap(syspath["profile_appdata"].."\\Baidu\\browser\\UserData\\0A73B7929C9546628F097CEEACA6E079410064006d0069006e006900730074007200610074006f007200\\cookie.db")
end

-- ************************************************************
-- Part II : Search Historiy
-- ************************************************************

Actions['search.baidu'] = function ()
	DeleteFileWrap(syspath["cookies"].."\\CASD6B09.txt")
	DeleteFileWrap(syspath["cookies"].."\\CASXYZ8P.txt")
	CleanDirWrap( syspath["cookies"] ,"*@baidu[1].txt" )
end

Actions['search.sogou'] = function ()
	CleanDirWrap( syspath["cookies"] ,"*@www.sogou[2].txt" )	
end

Actions['search.soso'] = function ()
	DeleteFileWrap(syspath["cookies"].."\\CA1BN1WW.txt")
end


-- ************************************************************
-- Part III : Flash Cookie Cleaning
-- ************************************************************

Actions['flash.cookie'] = function ()
	CleanDirWrap( syspath["profile_appdata"].."\\Macromedia\\Flash Player" ,"*.sol" )	
end
