2021-07-25 10:42:26 +00:00
|
|
|
using Flow.Launcher.Infrastructure.Logger;
|
2021-03-16 10:33:40 +00:00
|
|
|
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
2020-05-23 06:40:31 +00:00
|
|
|
using Microsoft.Search.Interop;
|
2020-05-18 14:11:37 +00:00
|
|
|
using System;
|
2020-05-18 12:23:20 +00:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Data.OleDb;
|
2021-07-25 09:58:21 +00:00
|
|
|
using System.Linq;
|
2022-08-16 22:45:36 +00:00
|
|
|
using System.Runtime.CompilerServices;
|
2021-07-25 07:48:57 +00:00
|
|
|
using System.Runtime.InteropServices;
|
2020-05-24 09:15:13 +00:00
|
|
|
using System.Text.RegularExpressions;
|
2021-01-02 14:01:15 +00:00
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2021-07-25 09:58:21 +00:00
|
|
|
using System.Windows;
|
2020-05-18 12:23:20 +00:00
|
|
|
|
|
|
|
|
namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|
|
|
|
{
|
2022-03-25 21:19:00 +00:00
|
|
|
internal static class WindowsIndex
|
2020-05-18 12:23:20 +00:00
|
|
|
{
|
2020-05-18 14:11:37 +00:00
|
|
|
|
2020-05-24 09:15:13 +00:00
|
|
|
// Reserved keywords in oleDB
|
2022-09-10 15:45:41 +00:00
|
|
|
private static Regex _reservedPatternMatcher = new(@"^[`\@\#\^,\&\/\\\$\%_;\[\]]+$", RegexOptions.Compiled);
|
2020-06-08 04:20:22 +00:00
|
|
|
|
2022-08-16 22:45:36 +00:00
|
|
|
private static async IAsyncEnumerable<SearchResult> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, [EnumeratorCancellation] CancellationToken token)
|
2020-05-18 12:23:20 +00:00
|
|
|
{
|
2022-08-16 22:45:36 +00:00
|
|
|
await using var conn = new OleDbConnection(connectionString);
|
|
|
|
|
await conn.OpenAsync(token);
|
|
|
|
|
token.ThrowIfCancellationRequested();
|
2020-05-18 12:23:20 +00:00
|
|
|
|
2022-08-16 22:45:36 +00:00
|
|
|
await using var command = new OleDbCommand(indexQueryString, conn);
|
|
|
|
|
// Results return as an OleDbDataReader.
|
2022-09-10 15:45:41 +00:00
|
|
|
OleDbDataReader dataReaderAttempt;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
dataReaderAttempt = await command.ExecuteReaderAsync(token) as OleDbDataReader;
|
|
|
|
|
}
|
|
|
|
|
catch (OleDbException e)
|
|
|
|
|
{
|
|
|
|
|
Log.Exception($"|WindowsIndex.ExecuteWindowsIndexSearchAsync|Failed to execute windows index search query: {indexQueryString}", e);
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
await using var dataReader = dataReaderAttempt;
|
2022-08-16 22:45:36 +00:00
|
|
|
token.ThrowIfCancellationRequested();
|
2020-05-18 14:11:37 +00:00
|
|
|
|
2022-09-10 15:45:41 +00:00
|
|
|
if (dataReader is not { HasRows: true })
|
2022-08-16 22:45:36 +00:00
|
|
|
{
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
2022-09-10 15:45:41 +00:00
|
|
|
|
|
|
|
|
while (await dataReader.ReadAsync(token))
|
2022-08-16 22:45:36 +00:00
|
|
|
{
|
2021-01-02 14:01:15 +00:00
|
|
|
token.ThrowIfCancellationRequested();
|
2022-09-10 15:45:41 +00:00
|
|
|
if (dataReader.GetValue(0) == DBNull.Value || dataReader.GetValue(1) == DBNull.Value)
|
2021-01-02 14:01:15 +00:00
|
|
|
{
|
2022-08-16 22:45:36 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
|
2022-09-10 15:45:41 +00:00
|
|
|
var encodedFragmentPath = dataReader
|
2022-08-16 22:45:36 +00:00
|
|
|
.GetString(1)
|
|
|
|
|
.Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
|
2021-01-02 14:01:15 +00:00
|
|
|
|
2022-08-16 22:45:36 +00:00
|
|
|
var path = new Uri(encodedFragmentPath).LocalPath;
|
2021-01-02 14:01:15 +00:00
|
|
|
|
2022-09-10 15:45:41 +00:00
|
|
|
yield return new SearchResult
|
2022-08-16 22:45:36 +00:00
|
|
|
{
|
|
|
|
|
FullPath = path,
|
2022-09-10 15:45:41 +00:00
|
|
|
Type = dataReader.GetString(2) == "Directory" ? ResultType.Folder : ResultType.File,
|
2022-08-16 22:45:36 +00:00
|
|
|
WindowsIndexed = true
|
|
|
|
|
};
|
2020-05-18 14:11:37 +00:00
|
|
|
}
|
2020-05-18 12:23:20 +00:00
|
|
|
|
2022-03-25 21:19:00 +00:00
|
|
|
// Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
|
2020-05-18 14:11:37 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-24 09:15:13 +00:00
|
|
|
|
2021-07-25 09:58:21 +00:00
|
|
|
|
2022-09-10 15:45:41 +00:00
|
|
|
internal static IAsyncEnumerable<SearchResult> WindowsIndexSearchAsync(string connectionString,
|
|
|
|
|
string search,
|
|
|
|
|
CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
return _reservedPatternMatcher.IsMatch(search)
|
|
|
|
|
? AsyncEnumerable.Empty<SearchResult>()
|
|
|
|
|
: ExecuteWindowsIndexSearchAsync(search, connectionString, token);
|
2021-03-16 10:33:40 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-10 15:45:41 +00:00
|
|
|
// TODO: Move to General Search Manager
|
2022-03-28 20:28:18 +00:00
|
|
|
private static void RemoveResultsInExclusionList(List<SearchResult> results, IReadOnlyList<AccessLink> exclusionList, CancellationToken token)
|
2021-03-16 10:33:40 +00:00
|
|
|
{
|
|
|
|
|
var indexExclusionListCount = exclusionList.Count;
|
|
|
|
|
|
|
|
|
|
if (indexExclusionListCount == 0)
|
2022-03-28 20:28:18 +00:00
|
|
|
return;
|
|
|
|
|
results.RemoveAll(searchResult =>
|
|
|
|
|
exclusionList.Any(exclude => searchResult.FullPath.StartsWith(exclude.Path, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
);
|
2020-05-18 12:23:20 +00:00
|
|
|
}
|
2020-05-23 06:40:31 +00:00
|
|
|
|
2021-01-29 10:40:51 +00:00
|
|
|
internal static bool PathIsIndexed(string path)
|
2020-05-23 06:40:31 +00:00
|
|
|
{
|
2021-07-25 07:48:57 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var csm = new CSearchManager();
|
|
|
|
|
var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
|
|
|
|
|
return indexManager.IncludedInCrawlScope(path) > 0;
|
|
|
|
|
}
|
2022-03-25 21:19:00 +00:00
|
|
|
catch (COMException)
|
2021-07-25 07:48:57 +00:00
|
|
|
{
|
|
|
|
|
// Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-23 06:40:31 +00:00
|
|
|
}
|
2020-06-08 09:01:32 +00:00
|
|
|
|
2022-09-10 15:45:41 +00:00
|
|
|
// TODO: Use a custom exception to handle this
|
2021-07-25 10:16:30 +00:00
|
|
|
private static List<Result> ResultForWindexSearchOff(string rawQuery)
|
|
|
|
|
{
|
|
|
|
|
var api = SearchManager.Context.API;
|
|
|
|
|
|
|
|
|
|
return new List<Result>
|
|
|
|
|
{
|
|
|
|
|
new Result
|
|
|
|
|
{
|
|
|
|
|
Title = api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"),
|
|
|
|
|
SubTitle = api.GetTranslation("plugin_explorer_windowsSearchServiceFix"),
|
|
|
|
|
Action = c =>
|
|
|
|
|
{
|
|
|
|
|
SearchManager.Settings.WarnWindowsSearchServiceOff = false;
|
|
|
|
|
|
2022-03-25 21:19:00 +00:00
|
|
|
var pluginsManagerPlugin = api.GetAllPlugins().FirstOrDefault(x => x.Metadata.ID == "9f8f9b14-2518-4907-b211-35ab6290dee7");
|
2021-07-25 10:42:26 +00:00
|
|
|
|
2021-07-25 10:44:04 +00:00
|
|
|
var actionKeywordCount = pluginsManagerPlugin.Metadata.ActionKeywords.Count;
|
2021-07-25 10:42:26 +00:00
|
|
|
|
|
|
|
|
if (actionKeywordCount > 1)
|
|
|
|
|
LogException("PluginsManager's action keyword has increased to more than 1, this does not allow for determining the " +
|
2022-03-25 21:19:00 +00:00
|
|
|
"right action keyword. Explorer's code for managing Windows Search service not running exception needs to be updated",
|
2021-07-25 10:42:26 +00:00
|
|
|
new InvalidOperationException());
|
|
|
|
|
|
2021-07-25 10:16:30 +00:00
|
|
|
if (MessageBox.Show(string.Format(api.GetTranslation("plugin_explorer_alternative"), Environment.NewLine),
|
2022-03-25 21:19:00 +00:00
|
|
|
api.GetTranslation("plugin_explorer_alternative_title"),
|
|
|
|
|
MessageBoxButton.YesNo) == MessageBoxResult.Yes
|
2021-07-25 10:42:26 +00:00
|
|
|
&& actionKeywordCount == 1)
|
2021-07-25 10:16:30 +00:00
|
|
|
{
|
2021-07-25 10:44:04 +00:00
|
|
|
api.ChangeQuery(string.Format("{0} install everything", pluginsManagerPlugin.Metadata.ActionKeywords[0]));
|
2021-07-25 10:16:30 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Clears the warning message because same query string will not alter the displayed result list
|
|
|
|
|
api.ChangeQuery(string.Empty);
|
|
|
|
|
|
|
|
|
|
api.ChangeQuery(rawQuery);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var mainWindow = Application.Current.MainWindow;
|
2021-11-27 02:51:45 +00:00
|
|
|
mainWindow.Show();
|
2021-07-25 10:16:30 +00:00
|
|
|
mainWindow.Focus();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
IcoPath = Constants.ExplorerIconImagePath
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-29 10:40:51 +00:00
|
|
|
private static void LogException(string message, Exception e)
|
2020-06-08 09:01:32 +00:00
|
|
|
{
|
|
|
|
|
#if DEBUG // Please investigate and handle error from index search
|
|
|
|
|
throw e;
|
|
|
|
|
#else
|
|
|
|
|
Log.Exception($"|Flow.Launcher.Plugin.Explorer.IndexSearch|{message}", e);
|
2022-03-25 21:19:00 +00:00
|
|
|
#endif
|
2020-06-08 09:01:32 +00:00
|
|
|
}
|
2020-05-18 12:23:20 +00:00
|
|
|
}
|
2022-09-10 15:45:41 +00:00
|
|
|
}
|