src/SettingsStore.cs
Rama main · réplica de lectura del repositorio original.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Script.Serialization;
namespace Clipman
{
internal sealed class SettingsStore
{
private const string PointerFileName = "settings-location.json";
public string AppDirectory { get; private set; }
public string AppSettingsDirectory { get; private set; }
public string SettingsDirectory { get; private set; }
public string SettingsPath { get; private set; }
private readonly Action<string, Exception> warningLogger;
public SettingsStore(string appDirectory, Action<string, Exception> warningLogger = null)
{
AppDirectory = appDirectory;
AppSettingsDirectory = Path.Combine(appDirectory, "Settings");
this.warningLogger = warningLogger;
SetActiveSettingsDirectory(AppSettingsDirectory);
}
public AppSettings Load()
{
Directory.CreateDirectory(AppSettingsDirectory);
ResolveSettingsLocationConflicts();
bool hasSavedMachineFolder;
var pointerFolder = LoadDataFolderPointer(out hasSavedMachineFolder);
var loaded = LoadBestSettings(pointerFolder, hasSavedMachineFolder);
SettingsPath = loaded.Path;
SettingsDirectory = Path.GetDirectoryName(SettingsPath) ?? AppSettingsDirectory;
SyncConflictResolver.ResolveSettingsConflicts(SettingsPath);
var hadSortDescending = SettingsFileContainsProperty(SettingsPath, "SortDescending");
var hadFileHistorySortDescending = SettingsFileContainsProperty(SettingsPath, "FileHistorySortDescending");
var hadUseDefaultDatabasePath = SettingsFileContainsProperty(SettingsPath, "UseDefaultDatabasePath");
var hadRememberDatabasePassword = SettingsFileContainsProperty(SettingsPath, "RememberDatabasePassword");
var hadLastSelectedHistoryTab = SettingsFileContainsProperty(SettingsPath, "LastSelectedHistoryTab");
var settings = loaded.Settings;
if (string.IsNullOrWhiteSpace(settings.ProtectedServerToken))
{
settings.ServerToken = ReadStringProperty(SettingsPath, "ServerToken");
}
if (!hadLastSelectedHistoryTab)
{
settings.LastSelectedHistoryTab = settings.LastSelectedTab == 1 ? HistoryTabs.Files : HistoryTabs.Text;
}
if (!hadRememberDatabasePassword && !string.IsNullOrWhiteSpace(settings.ProtectedDatabasePassword))
{
settings.RememberDatabasePassword = true;
}
if (!hadUseDefaultDatabasePath)
{
settings.UseDefaultDatabasePath = ShouldTreatAsDefaultDatabasePath(settings.DatabasePath);
}
Normalize(settings);
PrepareSettingsDirectoryFor(settings);
if (!hadSortDescending)
{
settings.SortDescending = DefaultSortDescending(settings.SortMode);
}
if (!hadFileHistorySortDescending)
{
settings.FileHistorySortDescending = DefaultFileHistorySortDescending(settings.FileHistorySortMode);
}
var loadedFromExistingSettings = File.Exists(SettingsPath);
try
{
Save(settings);
}
catch (Exception ex)
{
if (!loadedFromExistingSettings || !IsSettingsWriteException(ex)) throw;
if (warningLogger != null)
{
warningLogger(
"Clipman continued startup with its existing settings because the normalized settings file was temporarily unavailable for writing.",
ex);
}
}
return settings;
}
private static bool IsSettingsWriteException(Exception ex)
{
if (ex is IOException || ex is UnauthorizedAccessException) return true;
return ex != null && ex.InnerException != null && IsSettingsWriteException(ex.InnerException);
}
public void Save(AppSettings settings)
{
var previousDirectory = SettingsDirectory;
var previousPath = SettingsPath;
try
{
PrepareSettingsDirectoryFor(settings);
Directory.CreateDirectory(SettingsDirectory);
Normalize(settings);
JsonUtil.SaveAtomic(SettingsPath, settings);
SaveDataFolderPointer(SettingsDirectory);
}
catch
{
SettingsDirectory = previousDirectory;
SettingsPath = previousPath;
throw;
}
}
public string DatabasePassword(AppSettings settings)
{
if (settings == null || string.IsNullOrWhiteSpace(settings.ProtectedDatabasePassword)) return string.Empty;
return DatabasePasswordProtector.Unprotect(settings.ProtectedDatabasePassword);
}
private void Normalize(AppSettings settings)
{
if (settings.UseDefaultDatabasePath || string.IsNullOrWhiteSpace(settings.DatabasePath))
{
settings.DatabasePath = DefaultDatabasePath();
settings.UseDefaultDatabasePath = true;
}
settings.StorageMode = NormalizeStorageMode(settings.StorageMode);
settings.ServerUrl = ServerSettingsSanitizer.CleanUrl(settings.ServerUrl);
NormalizeServerCertificateAuthority(settings);
var plainServerToken = ServerSettingsSanitizer.CleanToken(settings.ServerToken);
if (plainServerToken.Length == 0 && !string.IsNullOrWhiteSpace(settings.ProtectedServerToken))
{
try
{
plainServerToken = ServerSettingsSanitizer.CleanToken(ServerTokenProtector.Unprotect(settings.ProtectedServerToken));
}
catch
{
settings.ProtectedServerToken = string.Empty;
}
}
settings.ServerToken = plainServerToken;
settings.ProtectedServerToken = plainServerToken.Length == 0 ? string.Empty : ServerTokenProtector.Protect(plainServerToken);
if (string.IsNullOrWhiteSpace(settings.ShowHistoryHotkey))
{
settings.ShowHistoryHotkey = "Ctrl+Alt+\\";
}
if (string.IsNullOrWhiteSpace(settings.ToggleActiveHotkey))
{
settings.ToggleActiveHotkey = "Ctrl+Alt+`";
}
settings.SaveCurrentClipboardHotkey = (settings.SaveCurrentClipboardHotkey ?? string.Empty).Trim();
settings.QuickClipHotkey = (settings.QuickClipHotkey ?? string.Empty).Trim();
if (settings.QuickCopyHotkeys == null)
{
settings.QuickCopyHotkeys = new List<QuickCopyBinding>();
}
settings.QuickCopyHotkeys = settings.QuickCopyHotkeys
.Where(b => b != null && !string.IsNullOrWhiteSpace(b.EntryId) && !string.IsNullOrWhiteSpace(b.Hotkey))
.GroupBy(b => b.EntryId.Trim(), StringComparer.OrdinalIgnoreCase)
.Select(g => new QuickCopyBinding
{
EntryId = g.First().EntryId.Trim(),
Hotkey = g.First().Hotkey.Trim(),
Mode = QuickPasteModes.Normalize(g.First().Mode)
})
.GroupBy(b => b.Hotkey, StringComparer.OrdinalIgnoreCase)
.Select(g => g.First())
.ToList();
if (settings.MaxHistoryEntries < 0)
{
settings.MaxHistoryEntries = 0;
}
if (settings.MaxHistoryDays < 0)
{
settings.MaxHistoryDays = 0;
}
settings.ClipMergeWindowMilliseconds = ClipMergeDetector.NormalizeWindow(settings.ClipMergeWindowMilliseconds);
settings.ClipMergeSeparatorMode = NormalizeClipMergeSeparatorMode(settings.ClipMergeSeparatorMode);
settings.ClipMergeCustomSeparator = settings.ClipMergeCustomSeparator ?? string.Empty;
settings.MultipleEntrySeparatorMode = MultipleEntrySeparator.NormalizeMode(settings.MultipleEntrySeparatorMode);
settings.MultipleEntryCustomSeparator = settings.MultipleEntryCustomSeparator ?? string.Empty;
if (settings.IgnoredProcesses == null)
{
settings.IgnoredProcesses = new List<string>();
}
if (string.IsNullOrWhiteSpace(settings.DeviceName))
{
settings.DeviceName = Environment.MachineName ?? string.Empty;
}
else
{
settings.DeviceName = settings.DeviceName.Trim();
}
if (string.IsNullOrWhiteSpace(settings.SortMode))
{
settings.SortMode = "LastUsed";
}
if (string.IsNullOrWhiteSpace(settings.FileHistorySortMode))
{
settings.FileHistorySortMode = "Manual";
}
settings.FileHistorySortMode = NormalizeFileHistorySortMode(settings.FileHistorySortMode);
if (string.IsNullOrWhiteSpace(settings.GroupFilter))
{
settings.GroupFilter = "All";
}
settings.HistoryFilterType = string.Equals(settings.HistoryFilterType, "Device", StringComparison.OrdinalIgnoreCase)
? "Device"
: "Group";
if (string.IsNullOrWhiteSpace(settings.DeviceFilter))
{
settings.DeviceFilter = "All";
}
if (string.IsNullOrWhiteSpace(settings.DuplicateMode))
{
settings.DuplicateMode = settings.RemoveDuplicates ? "MoveToTop" : "KeepBoth";
}
if (settings.LastSelectedTab < 0 || settings.LastSelectedTab > 1)
{
settings.LastSelectedTab = 0;
}
settings.LastSelectedHistoryTab = HistoryTabs.Normalize(settings.LastSelectedHistoryTab, settings.LinksHistoryEnabled, settings.RichTextHistoryEnabled);
settings.IncludeImagesInRichText = settings.RichTextHistoryEnabled && settings.IncludeImagesInRichText;
settings.AutoAddImageFilesToRichText = settings.IncludeImagesInRichText && settings.AutoAddImageFilesToRichText;
settings.HistoryTabOrder = HistoryTabs.NormalizeOrder(settings.HistoryTabOrder);
if (settings.LastPreferencesTab < 0 || settings.LastPreferencesTab > 5)
{
settings.LastPreferencesTab = 0;
}
settings.SensitiveDataMode = SensitiveDataExclusion.NormalizeMode(settings.SensitiveDataMode);
if (settings.SensitiveDataPresetIds == null)
{
settings.SensitiveDataPresetIds = new List<string>();
}
var knownSensitivePresets = new HashSet<string>(SensitiveDataExclusion.BuiltInPresets.Select(p => p.Id), StringComparer.OrdinalIgnoreCase);
settings.SensitiveDataPresetIds = settings.SensitiveDataPresetIds
.Where(id => !string.IsNullOrWhiteSpace(id) && knownSensitivePresets.Contains(id.Trim()))
.Select(id => id.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (settings.DiagnosticsFileHistoryLimit < 0)
{
settings.DiagnosticsFileHistoryLimit = 0;
}
if (settings.DiagnosticsFileHistoryLimit > 200)
{
settings.DiagnosticsFileHistoryLimit = 200;
}
if (!string.IsNullOrWhiteSpace(settings.ProtectedDatabasePassword))
{
settings.DatabaseEncryptionEnabled = true;
if (!settings.RememberDatabasePassword)
{
settings.ProtectedDatabasePassword = string.Empty;
}
}
if (!settings.DatabaseEncryptionEnabled)
{
settings.RememberDatabasePassword = false;
settings.ProtectedDatabasePassword = string.Empty;
}
if (!settings.RememberDatabasePassword)
{
settings.ProtectedDatabasePassword = string.Empty;
}
settings.PlainDatabasePassword = string.Empty;
}
private static string NormalizeClipMergeSeparatorMode(string value)
{
switch ((value ?? string.Empty).Trim().ToUpperInvariant())
{
case "BLANKLINE": return "BlankLine";
case "SPACE": return "Space";
case "COMMASPACE": return "CommaSpace";
case "CUSTOM": return "Custom";
case "NEWLINE":
default: return "NewLine";
}
}
private static string ReadStringProperty(string path, string propertyName)
{
try
{
if (!File.Exists(path)) return string.Empty;
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var data = serializer.Deserialize<Dictionary<string, object>>(File.ReadAllText(path));
if (data == null) return string.Empty;
foreach (var pair in data)
{
if (string.Equals(pair.Key, propertyName, StringComparison.OrdinalIgnoreCase))
{
return Convert.ToString(pair.Value) ?? string.Empty;
}
}
}
catch
{
}
return string.Empty;
}
private static string NormalizeStorageMode(string mode)
{
return string.Equals((mode ?? string.Empty).Trim(), "Server", StringComparison.OrdinalIgnoreCase)
? "Server"
: "File";
}
private void NormalizeServerCertificateAuthority(AppSettings settings)
{
if (string.IsNullOrWhiteSpace(settings.ServerCaCertPem))
{
settings.ServerCaCertPem = string.Empty;
settings.ServerCaHost = string.Empty;
return;
}
ServerCertificateAuthority authority;
string error;
if (!ServerSettingsSanitizer.TryParseCertificateAuthority(
settings.ServerCaCertPem,
settings.ServerUrl,
out authority,
out error))
{
throw new InvalidDataException("Clipman could not use the configured private certificate authority: " + error);
}
if (!string.IsNullOrWhiteSpace(settings.ServerCaHost) &&
!string.Equals(settings.ServerCaHost.Trim(), authority.Host, StringComparison.OrdinalIgnoreCase))
{
settings.ServerCaCertPem = string.Empty;
settings.ServerCaHost = string.Empty;
if (warningLogger != null)
{
warningLogger(
"Clipman removed the private certificate authority because the configured server host changed.",
null);
}
return;
}
settings.ServerCaCertPem = authority.Pem;
settings.ServerCaHost = authority.Host;
}
private LoadedSettings LoadBestSettings(string pointerFolder, bool hasSavedMachineFolder)
{
if (!string.IsNullOrWhiteSpace(pointerFolder))
{
var pointerSettingsPath = Path.Combine(pointerFolder, MachineSettingsFileName());
if (File.Exists(pointerSettingsPath))
{
try
{
return new LoadedSettings(pointerSettingsPath, JsonUtil.LoadRequired<AppSettings>(pointerSettingsPath));
}
catch (Exception ex)
{
throw new IOException(
"Clipman could not read the settings file in the configured data folder:\r\n\r\n" +
pointerSettingsPath +
"\r\n\r\nClipman did not switch to a different data folder. Restore access to this file, then start Clipman again.",
ex);
}
}
if (!Directory.Exists(pointerFolder))
{
throw new IOException(
"Clipman cannot reach the configured data folder:\r\n\r\n" +
pointerFolder +
"\r\n\r\nReconnect the drive, cloud service, or network share, then start Clipman again. " +
"Clipman did not switch to the default data folder.");
}
var databasePath = Path.Combine(pointerFolder, "clipman-history.clipdb");
if (hasSavedMachineFolder && !IsCurrentDefaultDatabasePath(databasePath))
{
// This pointer is saved after the machine settings. A visible cloud folder can still be missing its files.
throw new IOException(
"Clipman cannot find this computer's settings file in the configured data folder:\r\n\r\n" +
pointerSettingsPath +
"\r\n\r\nWait for the folder to sync, or restore the settings file, then start Clipman again. " +
"Clipman did not replace your settings or change the data folder.");
}
var localPath = Path.Combine(AppSettingsDirectory, MachineSettingsFileName());
AppSettings settings;
try
{
settings = File.Exists(localPath)
? JsonUtil.Load<AppSettings>(localPath)
: new AppSettings();
}
catch (Exception ex)
{
throw new IOException("Clipman could not read the local settings needed to initialize the selected data folder.", ex);
}
settings.DatabasePath = databasePath;
settings.UseDefaultDatabasePath = false;
return new LoadedSettings(pointerSettingsPath, settings);
}
var appSettingsPath = Path.Combine(AppSettingsDirectory, MachineSettingsFileName());
if (File.Exists(appSettingsPath))
{
try
{
return new LoadedSettings(appSettingsPath, JsonUtil.Load<AppSettings>(appSettingsPath));
}
catch (Exception ex)
{
throw new IOException("Clipman could not read its settings file:\r\n\r\n" + appSettingsPath, ex);
}
}
return new LoadedSettings(appSettingsPath, new AppSettings());
}
private string LoadDataFolderPointer(out bool hasSavedMachineFolder)
{
hasSavedMachineFolder = false;
var path = Path.Combine(AppSettingsDirectory, PointerFileName);
ResolveSettingsLocationConflicts();
if (!File.Exists(path)) return string.Empty;
try
{
var pointer = JsonUtil.Load<SettingsLocationPointer>(path);
if (pointer == null)
{
throw new InvalidDataException("The settings location pointer is empty or invalid.");
}
return pointer.FolderForMachine(MachineNameSafe(), out hasSavedMachineFolder);
}
catch (Exception ex)
{
throw new IOException(
"Clipman could not read its data-folder pointer:\r\n\r\n" +
path +
"\r\n\r\nClipman did not switch to the default data folder.",
ex);
}
}
private void SaveDataFolderPointer(string folder)
{
if (string.IsNullOrWhiteSpace(folder)) return;
Directory.CreateDirectory(AppSettingsDirectory);
var path = Path.Combine(AppSettingsDirectory, PointerFileName);
ResolveSettingsLocationConflicts();
var pointer = LoadSettingsLocationPointer(path);
if (pointer == null && File.Exists(path))
{
throw new IOException(
"Clipman could not update its data-folder pointer because the existing file is unreadable:\r\n\r\n" +
path);
}
pointer = pointer ?? new SettingsLocationPointer();
pointer.SetFolderForMachine(MachineNameSafe(), folder);
try
{
JsonUtil.SaveAtomic(path, pointer);
DeleteSettingsLocationConflicts(path);
}
catch (Exception ex)
{
throw new IOException(
"Clipman saved the settings but could not save the data-folder pointer:\r\n\r\n" +
path +
"\r\n\r\nThe selected data folder cannot be used safely until this pointer can be written.",
ex);
}
}
private void ResolveSettingsLocationConflicts()
{
try
{
var canonicalPath = Path.Combine(AppSettingsDirectory, PointerFileName);
var conflicts = SyncConflictResolver.FindConflictSiblings(canonicalPath).ToList();
if (conflicts.Count == 0) return;
var candidates = new List<Tuple<string, SettingsLocationPointer, DateTime>>();
AddSettingsLocationCandidate(candidates, canonicalPath);
foreach (var conflict in conflicts)
{
AddSettingsLocationCandidate(candidates, conflict);
}
var merged = MergeSettingsLocationPointers(candidates);
if (merged != null)
{
Directory.CreateDirectory(AppSettingsDirectory);
JsonUtil.SaveAtomic(canonicalPath, merged);
DeleteSettingsLocationConflicts(canonicalPath);
}
}
catch
{
}
}
private static void AddSettingsLocationCandidate(List<Tuple<string, SettingsLocationPointer, DateTime>> candidates, string path)
{
try
{
if (!File.Exists(path)) return;
candidates.Add(Tuple.Create(path, LoadSettingsLocationPointer(path), File.GetLastWriteTimeUtc(path)));
}
catch
{
}
}
private static SettingsLocationPointer LoadSettingsLocationPointer(string path)
{
try
{
if (!File.Exists(path)) return null;
var serializer = new JavaScriptSerializer();
var data = serializer.Deserialize<Dictionary<string, object>>(File.ReadAllText(path));
if (data == null) return null;
var pointer = new SettingsLocationPointer();
object dataFolder;
if (TryGetCaseInsensitive(data, "dataFolder", out dataFolder))
{
pointer.dataFolder = Convert.ToString(dataFolder) ?? string.Empty;
}
object clients;
if (TryGetCaseInsensitive(data, "clients", out clients))
{
var clientDictionary = clients as Dictionary<string, object>;
if (clientDictionary != null)
{
foreach (var pair in clientDictionary)
{
var value = Convert.ToString(pair.Value) ?? string.Empty;
if (!string.IsNullOrWhiteSpace(pair.Key) && !string.IsNullOrWhiteSpace(value))
{
pointer.clients[pair.Key.Trim()] = value;
}
}
}
}
return pointer;
}
catch
{
return null;
}
}
private static bool TryGetCaseInsensitive(Dictionary<string, object> data, string key, out object value)
{
foreach (var pair in data)
{
if (string.Equals(pair.Key, key, StringComparison.OrdinalIgnoreCase))
{
value = pair.Value;
return true;
}
}
value = null;
return false;
}
private static SettingsLocationPointer MergeSettingsLocationPointers(IEnumerable<Tuple<string, SettingsLocationPointer, DateTime>> candidates)
{
var merged = new SettingsLocationPointer();
var sawAny = false;
foreach (var item in candidates
.Where(candidate => candidate.Item2 != null)
.OrderBy(candidate => candidate.Item3))
{
var pointer = item.Item2;
if (IsValidSettingsLocation(pointer.dataFolder))
{
merged.dataFolder = pointer.dataFolder;
sawAny = true;
}
foreach (var pair in pointer.clients ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase))
{
if (string.IsNullOrWhiteSpace(pair.Key) || !IsValidSettingsLocation(pair.Value))
{
continue;
}
merged.clients[pair.Key.Trim()] = pair.Value;
sawAny = true;
}
}
return sawAny ? merged : null;
}
private static bool IsValidSettingsLocation(string folder)
{
if (string.IsNullOrWhiteSpace(folder)) return false;
try
{
Path.GetFullPath(folder);
return true;
}
catch
{
return false;
}
}
private static void DeleteSettingsLocationConflicts(string canonicalPath)
{
foreach (var conflict in SyncConflictResolver.FindConflictSiblings(canonicalPath))
{
try
{
File.Delete(conflict);
}
catch
{
}
}
}
private void PrepareSettingsDirectoryFor(AppSettings settings)
{
if (settings == null)
{
SetActiveSettingsDirectory(AppSettingsDirectory);
return;
}
if (settings.UseDefaultDatabasePath || string.IsNullOrWhiteSpace(settings.DatabasePath))
{
SetActiveSettingsDirectory(AppSettingsDirectory);
return;
}
try
{
var directory = Path.GetDirectoryName(Path.GetFullPath(settings.DatabasePath));
SetActiveSettingsDirectory(string.IsNullOrWhiteSpace(directory) ? AppSettingsDirectory : directory);
}
catch
{
SetActiveSettingsDirectory(AppSettingsDirectory);
}
}
private void SetActiveSettingsDirectory(string directory)
{
SettingsDirectory = string.IsNullOrWhiteSpace(directory) ? AppSettingsDirectory : directory;
SettingsPath = Path.Combine(SettingsDirectory, MachineSettingsFileName());
}
private bool SettingsFileContainsProperty(string settingsPath, string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName) || string.IsNullOrWhiteSpace(settingsPath) || !File.Exists(settingsPath))
{
return false;
}
try
{
var text = File.ReadAllText(settingsPath);
return text.IndexOf("\"" + propertyName + "\"", StringComparison.OrdinalIgnoreCase) >= 0;
}
catch
{
return false;
}
}
private static bool DefaultSortDescending(string sortMode)
{
switch ((sortMode ?? string.Empty).Trim().ToUpperInvariant())
{
case "TEXT":
case "GROUP":
case "MACHINE":
case "MANUAL":
return false;
default:
return true;
}
}
private static bool DefaultFileHistorySortDescending(string sortMode)
{
switch ((sortMode ?? string.Empty).Trim().ToUpperInvariant())
{
case "TIME":
return true;
default:
return false;
}
}
private static string NormalizeFileHistorySortMode(string sortMode)
{
switch ((sortMode ?? string.Empty).Trim().ToUpperInvariant())
{
case "TIME":
return "Time";
case "FILES":
return "Files";
case "NAME":
return "Name";
case "OPERATION":
return "Operation";
case "SOURCE":
return "Source";
case "MANUAL":
return "Manual";
default:
return "Manual";
}
}
public string DefaultDatabasePath()
{
return Path.Combine(SettingsDirectory, "clipman-history.clipdb");
}
public string EffectiveTextHistoryDatabasePath(AppSettings settings)
{
if (settings == null || !string.Equals(settings.StorageMode, "Server", StringComparison.OrdinalIgnoreCase))
{
return settings == null || string.IsNullOrWhiteSpace(settings.DatabasePath)
? DefaultDatabasePath()
: settings.DatabasePath;
}
var root = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
if (string.IsNullOrWhiteSpace(root))
{
root = Path.GetTempPath();
}
return Path.Combine(root, "Clipman", "ServerCache", Environment.MachineName, "clipman-history.clipdb");
}
public string DefaultFileHistoryDatabasePath()
{
return Path.Combine(SettingsDirectory, MachineNameSafe() + "-file-history.clipdb");
}
public string DefaultSecretsDatabasePath()
{
return Path.Combine(SettingsDirectory, MachineNameSafe() + "-secrets.clipdb");
}
private bool ShouldTreatAsDefaultDatabasePath(string databasePath)
{
if (string.IsNullOrWhiteSpace(databasePath)) return true;
if (IsCurrentDefaultDatabasePath(databasePath)) return true;
try
{
var full = Path.GetFullPath(databasePath);
var file = Path.GetFileName(full);
var parent = Directory.GetParent(full);
return string.Equals(file, "clipman-history.clipdb", StringComparison.OrdinalIgnoreCase) &&
parent != null &&
string.Equals(parent.Name, "Settings", StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
public bool IsCurrentDefaultDatabasePath(string databasePath)
{
if (string.IsNullOrWhiteSpace(databasePath)) return false;
try
{
return string.Equals(
Path.GetFullPath(databasePath),
Path.GetFullPath(Path.Combine(AppSettingsDirectory, "clipman-history.clipdb")),
StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
private static string MachineSettingsFileName()
{
return MachineNameSafe() + "-settings.json";
}
private static string MachineNameSafe()
{
var name = Environment.MachineName;
if (string.IsNullOrWhiteSpace(name))
{
name = "ThisComputer";
}
var invalid = Path.GetInvalidFileNameChars();
var safe = new string(name.Select(ch => invalid.Contains(ch) ? '_' : ch).ToArray()).Trim();
if (string.IsNullOrWhiteSpace(safe))
{
safe = "ThisComputer";
}
return safe;
}
private sealed class LoadedSettings
{
public string Path { get; private set; }
public AppSettings Settings { get; private set; }
public LoadedSettings(string path, AppSettings settings)
{
Path = path;
Settings = settings ?? new AppSettings();
}
}
private sealed class SettingsLocationPointer
{
public string dataFolder { get; set; }
public Dictionary<string, string> clients { get; set; }
public SettingsLocationPointer()
{
dataFolder = string.Empty;
clients = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
public string FolderForMachine(string machineName, out bool hasSavedMachineFolder)
{
hasSavedMachineFolder = false;
if (!string.IsNullOrWhiteSpace(machineName) && clients != null)
{
foreach (var pair in clients)
{
if (string.Equals(pair.Key, machineName, StringComparison.OrdinalIgnoreCase))
{
hasSavedMachineFolder = true;
return pair.Value ?? string.Empty;
}
}
}
return dataFolder ?? string.Empty;
}
public void SetFolderForMachine(string machineName, string folder)
{
if (clients == null)
{
clients = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
if (!string.IsNullOrWhiteSpace(machineName))
{
clients[machineName.Trim()] = folder ?? string.Empty;
}
}
}
}
}