2022-12-15 11:03:54 +00:00
|
|
|
|
using Flow.Launcher.Infrastructure.Logger;
|
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;
|
2022-09-22 00:18:20 +00:00
|
|
|
|
using Flow.Launcher.Plugin.Explorer.Exceptions;
|
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
|
2024-02-05 01:06:47 +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();
|
2023-08-07 12:18:49 +00:00
|
|
|
|
if (dataReader.GetValue(0) is DBNull
|
|
|
|
|
|
|| dataReader.GetValue(1) is not string rawFragmentPath
|
2023-08-07 12:54:30 +00:00
|
|
|
|
|| string.Equals(rawFragmentPath, "file:", StringComparison.OrdinalIgnoreCase)
|
|
|
|
|
|
|| dataReader.GetValue(2) is not string extension)
|
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
|
2023-08-07 12:18:49 +00:00
|
|
|
|
var encodedFragmentPath = rawFragmentPath.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,
|
2023-08-07 12:54:30 +00:00
|
|
|
|
Type = string.Equals(extension, "Directory", StringComparison.Ordinal) ? 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
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-01 12:02:43 +00:00
|
|
|
|
internal static IAsyncEnumerable<SearchResult> WindowsIndexSearchAsync(
|
|
|
|
|
|
string connectionString,
|
2022-09-10 15:45:41 +00:00
|
|
|
|
string search,
|
|
|
|
|
|
CancellationToken token)
|
|
|
|
|
|
{
|
2022-09-22 00:18:20 +00:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
return _reservedPatternMatcher.IsMatch(search)
|
|
|
|
|
|
? AsyncEnumerable.Empty<SearchResult>()
|
|
|
|
|
|
: ExecuteWindowsIndexSearchAsync(search, connectionString, token);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (InvalidOperationException e)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new SearchException("Windows Index", e.Message, e);
|
|
|
|
|
|
}
|
2021-03-16 10:33:40 +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-05-18 12:23:20 +00:00
|
|
|
|
}
|
2022-09-10 15:45:41 +00:00
|
|
|
|
}
|