<commit_before>﻿/*
    Copyright (c) 2017 <NAME> (https://github.com/Klocman/)
    Apache License Version 2.0
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using Klocman.Extensions;
using Klocman.Native;
using Klocman.Tools;
using Microsoft.Win32;

namespace UninstallTools.Junk
{
    public class RegistryJunk : JunkBase
    {
        private const string KeynameRegisteredApps = "RegisteredApplications";

        /// <summary>
        ///     Keys to step over when scanning
        /// </summary>
        private static readonly IEnumerable<string> KeyBlacklist = new[]
        {
            "Microsoft", "Wow6432Node", "Windows", "Classes", "Clients", KeynameRegisteredApps
        };

        /// <summary>
        ///     Always points to program's directory
        /// </summary>
        private static readonly IEnumerable<string> InstallDirKeyNames = new[]
        {
            "InstallDir",
            "Install_Dir",
            "Install Directory",
            "InstDir",
            "ApplicationPath",
            "Install folder",
            "Last Stable Install Path",
            "TARGETDIR",
            "JavaHome"
        };

        /// <summary>
        ///     Always points to program's main executable
        /// </summary>
        private static readonly IEnumerable<string> ExePathKeyNames = new[]
        {
            "exe64",
            "exe32",
            "Executable",
            "PathToExe",
            "ExePath"
        };

        /// <summary>
        ///     Can point to programs executable or directory
        /// </summary>
        private static readonly IEnumerable<string> ExeOrDirPathKeyNames = new[]
        {
            "Path",
            "Path64",
            "pth",
            "PlayerPath",
            "AppPath"
        };

        private static readonly IEnumerable<string> UserAssistGuids = new[]
        {
            //GUIDs for Windows XP
            "{75048700-EF1F-11D0-9888-006097DEACF9}",
            "{5E6AB780-7743-11CF-A12B-00AA004AE837",
            //GUIDs for Windows 7
            "{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}",
            "{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}}"
        };

        private static readonly string KeyCu = @"HKEY_CURRENT_USER\SOFTWARE";
        private static readonly string KeyCuWow = @"HKEY_CURRENT_USER\SOFTWARE\Wow6432Node";
        private static readonly string KeyLm = @"HKEY_LOCAL_MACHINE\SOFTWARE";
        private static readonly string KeyLmWow = @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node";

        private static readonly string[] SoftwareRegKeys = ProcessTools.Is64BitProcess
            ? new[] { KeyLm, KeyCu, KeyLmWow, KeyCuWow }
            : new[] { KeyLm, KeyCu };

        private static readonly string[] ClsidKeys =
        {
            @"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID",
            @"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\CLSID",
            @"HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID",
            @"HKEY_CURRENT_USER\SOFTWARE\Classes\WOW6432Node\CLSID"
        };

        public RegistryJunk(ApplicationUninstallerEntry entry,
            IEnumerable<ApplicationUninstallerEntry> otherUninstallers)
            : base(entry, otherUninstallers)
        {
        }

        public override IEnumerable<JunkNode> FindJunk()
        {
            var returnList = new List<JunkNode>();

            returnList.AddRange(ScanForJunk());

            returnList.AddRange(ScanFirewallRules());

            returnList.AddRange(ScanTracing());

            returnList.AddRange(ScanClsid());

            returnList.AddRange(ScanAudioPolicyConfig());

            returnList.AddRange(ScanUserAssist());

            returnList.AddRange(ScanEventLogs());

            returnList.AddRange(ScanInstallerFolders());

            if (Uninstaller.RegKeyStillExists())
            {
                var regKeyNode = new RegistryKeyJunkNode(PathTools.GetDirectory(Uninstaller.RegistryPath),
                    Uninstaller.RegistryKeyName, Uninstaller.DisplayName);
                regKeyNode.Confidence.Add(ConfidencePart.IsUninstallerRegistryKey);
                returnList.Add(regKeyNode);
            }

            return returnList;
        }

        private IEnumerable<JunkNode> ScanInstallerFolders()
        {
            var installLocation = Uninstaller.InstallLocation;
            if (string.IsNullOrEmpty(installLocation)) yield break;

            using (var key = Registry.LocalMachine.OpenSubKey(
                @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\Folders"))
            {
                if (key == null) yield break;

                foreach (var path in key.GetValueNames())
                {
                    if (!TestPathsMatch(installLocation, path)) continue;

                    var node = new RegistryValueJunkNode(key.Name, path, Uninstaller.DisplayName);
                    node.Confidence.Add(ConfidencePart.ExplicitConnection);

                    if (OtherUninstallers.Any(x => TestPathsMatch(x.InstallLocation, path)))
                        node.Confidence.Add(ConfidencePart.DirectoryStillUsed);

                    yield return node;
                }
            }
        }

        private IEnumerable<JunkNode> ScanEventLogs()
        {
            if (string.IsNullOrEmpty(Uninstaller.InstallLocation)) yield break;

            using (var key = Registry.LocalMachine.OpenSubKey(
                @"SYSTEM\CurrentControlSet\Services\EventLog\Application"))
            {
                if (key == null) yield break;

                var query = from name in key.GetSubKeyNames()
                            let m = MatchStringToProductName(name)
                            where m >= 0 && m < 3
                            //orderby m ascending
                            select name;

                foreach (var result in query)
                {
                    using (var subkey = key.OpenSubKey(result))
                    {
                        var exePath = subkey?.GetValue("EventMessageFile") as string;
                        if (string.IsNullOrEmpty(exePath) || !TestPathsMatchExe(exePath)) continue;

                        var node = new RegistryKeyJunkNode(key.Name, result, Uninstaller.DisplayName);
                        // Already matched names above
                        node.Confidence.Add(ConfidencePart.ProductNamePerfectMatch);

                        if (OtherUninstallers.Any(x => TestPathsMatch(x.InstallLocation, Path.GetDirectoryName(exePath))))
                            node.Confidence.Add(ConfidencePart.DirectoryStillUsed);

                        yield return node;
                    }
                }<commit_msg>Added searching for application compatibility registry junk; Partial #76<commit_after>﻿/*
    Copyright (c) 2017 <NAME> (https://github.com/Klocman/)
    Apache License Version 2.0
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using Klocman.Extensions;
using Klocman.Native;
using Klocman.Tools;
using Microsoft.Win32;

namespace UninstallTools.Junk
{
    public class RegistryJunk : JunkBase
    {
        private const string KeynameRegisteredApps = "RegisteredApplications";

        /// <summary>
        ///     Keys to step over when scanning
        /// </summary>
        private static readonly IEnumerable<string> KeyBlacklist = new[]
        {
            "Microsoft", "Wow6432Node", "Windows", "Classes", "Clients", KeynameRegisteredApps
        };

        /// <summary>
        ///     Always points to program's directory
        /// </summary>
        private static readonly IEnumerable<string> InstallDirKeyNames = new[]
        {
            "InstallDir",
            "Install_Dir",
            "Install Directory",
            "InstDir",
            "ApplicationPath",
            "Install folder",
            "Last Stable Install Path",
            "TARGETDIR",
            "JavaHome"
        };

        /// <summary>
        ///     Always points to program's main executable
        /// </summary>
        private static readonly IEnumerable<string> ExePathKeyNames = new[]
        {
            "exe64",
            "exe32",
            "Executable",
            "PathToExe",
            "ExePath"
        };

        /// <summary>
        ///     Can point to programs executable or directory
        /// </summary>
        private static readonly IEnumerable<string> ExeOrDirPathKeyNames = new[]
        {
            "Path",
            "Path64",
            "pth",
            "PlayerPath",
            "AppPath"
        };

        private static readonly IEnumerable<string> UserAssistGuids = new[]
        {
            //GUIDs for Windows XP
            "{75048700-EF1F-11D0-9888-006097DEACF9}",
            "{5E6AB780-7743-11CF-A12B-00AA004AE837",
            //GUIDs for Windows 7
            "{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}",
            "{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}}"
        };

        private static readonly IEnumerable<string> AppCompatFlags = new[]
        {
            @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags",
            @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags"
        };

        private static readonly string KeyCu = @"HKEY_CURRENT_USER\SOFTWARE";
        private static readonly string KeyCuWow = @"HKEY_CURRENT_USER\SOFTWARE\Wow6432Node";
        private static readonly string KeyLm = @"HKEY_LOCAL_MACHINE\SOFTWARE";
        private static readonly string KeyLmWow = @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node";

        private static readonly string[] SoftwareRegKeys = ProcessTools.Is64BitProcess
            ? new[] { KeyLm, KeyCu, KeyLmWow, KeyCuWow }
            : new[] { KeyLm, KeyCu };

        private static readonly string[] ClsidKeys =
        {
            @"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID",
            @"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\CLSID",
            @"HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID",
            @"HKEY_CURRENT_USER\SOFTWARE\Classes\WOW6432Node\CLSID"
        };

        public RegistryJunk(ApplicationUninstallerEntry entry,
            IEnumerable<ApplicationUninstallerEntry> otherUninstallers)
            : base(entry, otherUninstallers)
        {
        }

        public override IEnumerable<JunkNode> FindJunk()
        {
            var returnList = new List<JunkNode>();

            returnList.AddRange(ScanForJunk());

            returnList.AddRange(ScanFirewallRules());

            returnList.AddRange(ScanTracing());

            returnList.AddRange(ScanClsid());

            returnList.AddRange(ScanAudioPolicyConfig());

            returnList.AddRange(ScanUserAssist());

            returnList.AddRange(ScanAppCompatFlags());

            returnList.AddRange(ScanEventLogs());

            returnList.AddRange(ScanInstallerFolders());

            if (Uninstaller.RegKeyStillExists())
            {
                var regKeyNode = new RegistryKeyJunkNode(PathTools.GetDirectory(Uninstaller.RegistryPath),
                    Uninstaller.RegistryKeyName, Uninstaller.DisplayName);
                regKeyNode.Confidence.Add(ConfidencePart.IsUninstallerRegistryKey);
                returnList.Add(regKeyNode);
            }

            return returnList;
        }

        private IEnumerable<JunkNode> ScanInstallerFolders()
        {
            var installLocation = Uninstaller.InstallLocation;
            if (string.IsNullOrEmpty(installLocation)) yield break;

            using (var key = Registry.LocalMachine.OpenSubKey(
                @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\Folders"))
            {
                if (key == null) yield break;

                foreach (var path in key.GetValueNames())
                {
                    if (!TestPathsMatch(installLocation, path)) continue;

                    var node = new RegistryValueJunkNode(key.Name, path, Uninstaller.DisplayName);
                    node.Confidence.Add(ConfidencePart.ExplicitConnection);

                    if (OtherUninstallers.Any(x => TestPathsMatch(x.InstallLocation, path)))
                        node.Confidence.Add(ConfidencePart.DirectoryStillUsed);

                    yield return node;
                }
            }
        }

        private IEnumerable<JunkNode> ScanEventLogs()
        {
            if (string.IsNullOrEmpty(Uninstaller.InstallLocation)) yield break;

            using (var key = Registry.LocalMachine.OpenSubKey(
                @"SYSTEM\CurrentControlSet\Services\EventLog\Application"))
            {
                if (key == null) yield break;

                var query = from name in key.GetSubKeyNames()
                            let m = MatchStringToProductName(name)
                            where m >= 0 && m < 3
                            //orderby m ascending
                            select name;

                foreach (var result in query)
                {
                    using (var subkey = key.OpenSubKey(result))
                    {
                        var exePath = subkey?.GetValue("EventMessageFile") as string;
                        if (string.IsNullOrEmpty(exePath) || !TestPathsMatchExe(exePath)) continue;

                        var node = new RegistryKeyJunkNode(key.Name, result, Uninstaller.DisplayName);
                        // Already matched names above
                        node.Confidence.Add(ConfidencePart.ProductNamePerfectMatch);

                        if (OtherUninstallers.Any(x => TestPathsMatch(x.InstallLocation, Path.GetDirectoryName(exePath))))
                            node.Confidence.Add(ConfidencePart.DirectoryStillUsed);

                        yield return node;
                    }
                }
            }
        }

        private IEnumerable<JunkNode> ScanAppCompatFlags()
        {
            if (string.IsNullOrEmpty(Uninstaller.InstallLocation))
                yield break;

            foreach (var fullCompatKey in AppCompatFlags.SelectMany(compatKey => new[]
            {
                compatKey + @"\Layers" ,
                compatKey + @"\Compatibility Assistant\Store"
            }))
            {
                using (var key = RegistryTools.OpenRegistryKey(fullCompatKey))
                {
                    if (key == null)
                        continue;

                    foreach (var valueName in key.GetValueNames())
                    {
                        // Check for matches
                        if (valueName.StartsWith(Uninstaller.InstallLocation,
                            StringComparison.InvariantCultureIgnoreCase))
                        {
                            var junk = new RegistryValueJunkNode(key.Name, valueName, Uninstaller.DisplayName);
                            junk.Confidence.Add(ConfidencePart.ExplicitConnection);
                            yield return junk;
                        }
                    }
                }
{'fraction_non_alphanumeric': 0.09140599275600922, 'fraction_numerical': 0.01567336187026671, 'mean_word_length': 1.7352305475504324, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 50, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '401710', 'n_tokens_mistral': 4195, 'n_tokens_neox': 3842, 'n_words': 754}