diff --git a/Source/NETworkManager.Models/HostsFileEditor/HostsFileEditor.cs b/Source/NETworkManager.Models/HostsFileEditor/HostsFileEditor.cs index daca58dbe5..82e1817247 100644 --- a/Source/NETworkManager.Models/HostsFileEditor/HostsFileEditor.cs +++ b/Source/NETworkManager.Models/HostsFileEditor/HostsFileEditor.cs @@ -132,16 +132,16 @@ private static IEnumerable GetHostsFileEntries() if (result.Success) { - Log.Debug("GetHostsFileEntries - Line matched: " + line); + Log.Debug($"GetHostsFileEntries - Line matched: {line}"); var entry = new HostsFileEntry - { - IsEnabled = !result.Groups[1].Value.Equals("#"), - IPAddress = result.Groups[2].Value, - Hostname = result.Groups[3].Value.Replace(@"\s", "").Trim(), - Comment = result.Groups[4].Value.TrimStart('#', ' '), - Line = line - }; + ( + !result.Groups[1].Value.Equals("#"), + result.Groups[2].Value, + result.Groups[3].Value.Replace(@"\s", "").Trim(), + result.Groups[4].Value.TrimStart('#', ' '), + line + ); // Skip example entries if (!entry.IsEnabled) @@ -157,7 +157,7 @@ private static IEnumerable GetHostsFileEntries() } else { - Log.Debug("GetHostsFileEntries - Line not matched: " + line); + Log.Debug($"GetHostsFileEntries - Line not matched: {line}"); } } @@ -201,31 +201,34 @@ private static HostsFileEntryModifyResult EnableEntry(HostsFileEntry entry) return HostsFileEntryModifyResult.ReadError; } - bool entryFound = false; + var entryFound = false; for (var i = 0; i < hostsFileLines.Count; i++) { - if (hostsFileLines[i] == entry.Line) - { - entryFound = true; + if (hostsFileLines[i] != entry.Line) + continue; - hostsFileLines.RemoveAt(i); - hostsFileLines.Insert(i, CreateEntryLine(new HostsFileEntry - { - IsEnabled = true, - IPAddress = entry.IPAddress, - Hostname = entry.Hostname, - Comment = entry.Comment, - Line = entry.Line - })); - - break; - } + entryFound = true; + + Log.Debug($"EnableEntry - Found entry: {hostsFileLines[i]}"); + hostsFileLines.RemoveAt(i); + + var newEntry = new HostsFileEntry( + true, + entry.IPAddress, + entry.Hostname, + entry.Comment + ); + + Log.Debug($"EnableEntry - Enabling entry: {newEntry.Line}"); + hostsFileLines.Insert(i, newEntry.Line); + + break; } if (!entryFound) { - Log.Warn($"EnableEntry - Entry not found in hosts file: {entry.Line}"); + Log.Warn($"EnableEntry - Entry not found in hosts file: {entry}"); return HostsFileEntryModifyResult.NotFound; } @@ -281,26 +284,29 @@ private static HostsFileEntryModifyResult DisableEntry(HostsFileEntry entry) return HostsFileEntryModifyResult.ReadError; } - bool entryFound = false; + var entryFound = false; for (var i = 0; i < hostsFileLines.Count; i++) { - if (hostsFileLines[i] == entry.Line) - { - entryFound = true; + if (hostsFileLines[i] != entry.Line) + continue; - hostsFileLines.RemoveAt(i); - hostsFileLines.Insert(i, CreateEntryLine(new HostsFileEntry - { - IsEnabled = false, - IPAddress = entry.IPAddress, - Hostname = entry.Hostname, - Comment = entry.Comment, - Line = entry.Line - })); - - break; - } + entryFound = true; + + Log.Debug($"DisableEntry - Found entry: {hostsFileLines[i]}"); + hostsFileLines.RemoveAt(i); + + var newEntry = new HostsFileEntry( + false, + entry.IPAddress, + entry.Hostname, + entry.Comment + ); + + Log.Debug($"DisableEntry - Disabling entry: {newEntry.Line}"); + hostsFileLines.Insert(i, newEntry.Line); + + break; } if (!entryFound) @@ -360,7 +366,8 @@ private static HostsFileEntryModifyResult AddEntry(HostsFileEntry entry) return HostsFileEntryModifyResult.ReadError; } - hostsFileLines.Add(CreateEntryLine(entry)); + Log.Debug($"AddEntry - Adding entry: {entry.Line}"); + hostsFileLines.Add(entry.Line); try { @@ -415,19 +422,22 @@ private static HostsFileEntryModifyResult EditEntry(HostsFileEntry entry, HostsF return HostsFileEntryModifyResult.ReadError; } - bool entryFound = false; + var entryFound = false; for (var i = 0; i < hostsFileLines.Count; i++) { - if (hostsFileLines[i] == entry.Line) - { - entryFound = true; + if (hostsFileLines[i] != entry.Line) + continue; - hostsFileLines.RemoveAt(i); - hostsFileLines.Insert(i, CreateEntryLine(newEntry)); + entryFound = true; - break; - } + Log.Debug($"EditEntry - Found entry: {hostsFileLines[i]}"); + hostsFileLines.RemoveAt(i); + + Log.Debug($"EditEntry - Editing entry: {newEntry.Line}"); + hostsFileLines.Insert(i, newEntry.Line); + + break; } if (!entryFound) @@ -487,18 +497,19 @@ private static HostsFileEntryModifyResult DeleteEntry(HostsFileEntry entry) return HostsFileEntryModifyResult.ReadError; } - bool entryFound = false; + var entryFound = false; for (var i = 0; i < hostsFileLines.Count; i++) { - if (hostsFileLines[i] == entry.Line) - { - entryFound = true; + if (hostsFileLines[i] != entry.Line) + continue; - hostsFileLines.RemoveAt(i); + entryFound = true; - break; - } + Log.Debug($"DeleteEntry - Found entry: {hostsFileLines[i]}"); + hostsFileLines.RemoveAt(i); + + break; } if (!entryFound) @@ -521,25 +532,6 @@ private static HostsFileEntryModifyResult DeleteEntry(HostsFileEntry entry) return HostsFileEntryModifyResult.Success; } - /// - /// Create a line for the hosts file entry. - /// - /// Entry to create the line for. - /// Line for the hosts file entry. - private static string CreateEntryLine(HostsFileEntry entry) - { - var line = entry.IsEnabled ? "" : "# "; - - line += $"{entry.IPAddress} {entry.Hostname}"; - - if (!string.IsNullOrWhiteSpace(entry.Comment)) - { - line += $" # {entry.Comment}"; - } - - return line.Trim(); - } - /// /// Create a "daily" backup of the hosts file (before making a change). /// diff --git a/Source/NETworkManager.Models/HostsFileEditor/HostsFileEntry.cs b/Source/NETworkManager.Models/HostsFileEditor/HostsFileEntry.cs index eecb1d7da1..301062eee5 100644 --- a/Source/NETworkManager.Models/HostsFileEditor/HostsFileEntry.cs +++ b/Source/NETworkManager.Models/HostsFileEditor/HostsFileEntry.cs @@ -52,6 +52,15 @@ public HostsFileEntry(bool isEnabled, string ipAddress, string hostname, string IPAddress = ipAddress; Hostname = hostname; Comment = comment; + + var line = isEnabled ? "" : "# "; + + line += $"{ipAddress} {hostname}"; + + if (!string.IsNullOrWhiteSpace(comment)) + line += $" # {comment}"; + + Line = line; } /// @@ -62,8 +71,21 @@ public HostsFileEntry(bool isEnabled, string ipAddress, string hostname, string /// Host name(s) of the host. /// Comment of the host. /// Line of the entry in the hosts file. - public HostsFileEntry(bool isEnabled, string ipAddress, string hostname, string comment, string line) : this(isEnabled, ipAddress, hostname, comment) + public HostsFileEntry(bool isEnabled, string ipAddress, string hostname, string comment, string line) { + IsEnabled = isEnabled; + IPAddress = ipAddress; + Hostname = hostname; + Comment = comment; Line = line; } + + /// + /// Overrides the ToString method to return the line of the entry in the hosts file. + /// + /// Line of the entry in the hosts file. + public override string ToString() + { + return Line; + } } diff --git a/Source/NETworkManager/ViewModels/HostsFileEditorViewModel.cs b/Source/NETworkManager/ViewModels/HostsFileEditorViewModel.cs index d3c56296bb..f08b0c3ae7 100644 --- a/Source/NETworkManager/ViewModels/HostsFileEditorViewModel.cs +++ b/Source/NETworkManager/ViewModels/HostsFileEditorViewModel.cs @@ -23,6 +23,7 @@ namespace NETworkManager.ViewModels; public class HostsFileEditorViewModel : ViewModelBase { #region Variables + private static readonly ILog Log = LogManager.GetLogger(typeof(HostsFileEditorViewModel)); private readonly IDialogCoordinator _dialogCoordinator; @@ -30,6 +31,7 @@ public class HostsFileEditorViewModel : ViewModelBase private readonly bool _isLoading; private string _search; + public string Search { get => _search; @@ -183,10 +185,7 @@ public HostsFileEditorViewModel(IDialogCoordinator instance) // Watch hosts file for changes HostsFileEditor.HostsFileChanged += (_, _) => { - Application.Current.Dispatcher.Invoke(() => - { - Refresh().ConfigureAwait(false); - }); + Application.Current.Dispatcher.Invoke(() => { Refresh().ConfigureAwait(false); }); }; _isLoading = false; @@ -194,12 +193,12 @@ public HostsFileEditorViewModel(IDialogCoordinator instance) private void LoadSettings() { - } #endregion #region ICommands & Actions + public ICommand RefreshCommand => new RelayCommand(_ => RefreshAction().ConfigureAwait(false), Refresh_CanExecute); private bool Refresh_CanExecute(object parameter) @@ -223,38 +222,40 @@ private Task ExportAction() var childWindow = new ExportChildWindow(); var childWindowViewModel = new ExportViewModel(async instance => - { - childWindow.IsOpen = false; - ConfigurationManager.Current.IsChildWindowOpen = false; - - try { - ExportManager.Export(instance.FilePath, instance.FileType, - instance.ExportAll - ? Results - : new ObservableCollection(SelectedResults.Cast().ToArray())); - } - catch (Exception ex) + childWindow.IsOpen = false; + ConfigurationManager.Current.IsChildWindowOpen = false; + + try + { + ExportManager.Export(instance.FilePath, instance.FileType, + instance.ExportAll + ? Results + : new ObservableCollection(SelectedResults.Cast() + .ToArray())); + } + catch (Exception ex) + { + Log.Error("Error while exporting data as " + instance.FileType, ex); + + var settings = AppearanceManager.MetroDialog; + settings.AffirmativeButtonText = Strings.OK; + + await _dialogCoordinator.ShowMessageAsync(this, Strings.Error, + Strings.AnErrorOccurredWhileExportingTheData + Environment.NewLine + + Environment.NewLine + ex.Message, MessageDialogStyle.Affirmative, settings); + } + + SettingsManager.Current.HostsFileEditor_ExportFileType = instance.FileType; + SettingsManager.Current.HostsFileEditor_ExportFilePath = instance.FilePath; + }, _ => { - Log.Error("Error while exporting data as " + instance.FileType, ex); - - var settings = AppearanceManager.MetroDialog; - settings.AffirmativeButtonText = Strings.OK; - - await _dialogCoordinator.ShowMessageAsync(this, Strings.Error, - Strings.AnErrorOccurredWhileExportingTheData + Environment.NewLine + - Environment.NewLine + ex.Message, MessageDialogStyle.Affirmative, settings); - } - - SettingsManager.Current.HostsFileEditor_ExportFileType = instance.FileType; - SettingsManager.Current.HostsFileEditor_ExportFilePath = instance.FilePath; - }, _ => - { - childWindow.IsOpen = false; - ConfigurationManager.Current.IsChildWindowOpen = false; - }, [ - ExportFileType.Csv, ExportFileType.Xml, ExportFileType.Json - ], true, SettingsManager.Current.HostsFileEditor_ExportFileType, SettingsManager.Current.HostsFileEditor_ExportFilePath); + childWindow.IsOpen = false; + ConfigurationManager.Current.IsChildWindowOpen = false; + }, [ + ExportFileType.Csv, ExportFileType.Xml, ExportFileType.Json + ], true, SettingsManager.Current.HostsFileEditor_ExportFileType, + SettingsManager.Current.HostsFileEditor_ExportFilePath); childWindow.Title = Strings.Export; @@ -265,7 +266,8 @@ await _dialogCoordinator.ShowMessageAsync(this, Strings.Error, return (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow); } - public ICommand EnableEntryCommand => new RelayCommand(_ => EnableEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); + public ICommand EnableEntryCommand => + new RelayCommand(_ => EnableEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); private async Task EnableEntryAction() { @@ -279,7 +281,8 @@ private async Task EnableEntryAction() IsModifying = false; } - public ICommand DisableEntryCommand => new RelayCommand(_ => DisableEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); + public ICommand DisableEntryCommand => + new RelayCommand(_ => DisableEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); private async Task DisableEntryAction() { @@ -293,7 +296,8 @@ private async Task DisableEntryAction() IsModifying = false; } - public ICommand AddEntryCommand => new RelayCommand(_ => AddEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); + public ICommand AddEntryCommand => + new RelayCommand(_ => AddEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); private async Task AddEntryAction() { @@ -307,12 +311,13 @@ private async Task AddEntryAction() ConfigurationManager.Current.IsChildWindowOpen = false; var result = await HostsFileEditor.AddEntryAsync(new HostsFileEntry - { - IsEnabled = instance.IsEnabled, - IPAddress = instance.IPAddress, - Hostname = instance.Hostname, - Comment = instance.Comment - }); + ( + instance.IsEnabled, + instance.IPAddress, + instance.Hostname, + instance.Comment + ) + ); if (result != HostsFileEntryModifyResult.Success) await ShowErrorMessageAsync(result); @@ -335,35 +340,8 @@ private async Task AddEntryAction() await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow); } - private async Task ShowErrorMessageAsync(HostsFileEntryModifyResult result) - { - string message = result switch - { - HostsFileEntryModifyResult.ReadError => Strings.HostsFileReadErrorMessage, - HostsFileEntryModifyResult.WriteError => Strings.HostsFileWriteErrorMessage, - HostsFileEntryModifyResult.NotFound => Strings.HostsFileEntryNotFoundMessage, - HostsFileEntryModifyResult.BackupError => Strings.HostsFileBackupErrorMessage, - _ => Strings.UnkownError - }; - - var childWindow = new OKMessageChildWindow(); - - var childWindowViewModel = new OKMessageViewModel(_ => - { - childWindow.IsOpen = false; - ConfigurationManager.Current.IsChildWindowOpen = false; - }, message); - - childWindow.Title = Strings.Error; - - childWindow.DataContext = childWindowViewModel; - - ConfigurationManager.Current.IsChildWindowOpen = true; - - await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow); - } - - public ICommand EditEntryCommand => new RelayCommand(_ => EditEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); + public ICommand EditEntryCommand => + new RelayCommand(_ => EditEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); private async Task EditEntryAction() { @@ -377,12 +355,13 @@ private async Task EditEntryAction() ConfigurationManager.Current.IsChildWindowOpen = false; var result = await HostsFileEditor.EditEntryAsync(instance.Entry, new HostsFileEntry - { - IsEnabled = instance.IsEnabled, - IPAddress = instance.IPAddress, - Hostname = instance.Hostname, - Comment = instance.Comment - }); + ( + instance.IsEnabled, + instance.IPAddress, + instance.Hostname, + instance.Comment + ) + ); if (result != HostsFileEntryModifyResult.Success) await ShowErrorMessageAsync(result); @@ -405,7 +384,8 @@ private async Task EditEntryAction() await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow); } - public ICommand DeleteEntryCommand => new RelayCommand(_ => DeleteEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); + public ICommand DeleteEntryCommand => + new RelayCommand(_ => DeleteEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute); private async Task DeleteEntryAction() { @@ -414,24 +394,25 @@ private async Task DeleteEntryAction() var childWindow = new OKCancelInfoMessageChildWindow(); var childWindowViewModel = new OKCancelInfoMessageViewModel(async _ => - { - childWindow.IsOpen = false; - ConfigurationManager.Current.IsChildWindowOpen = false; + { + childWindow.IsOpen = false; + ConfigurationManager.Current.IsChildWindowOpen = false; - var result = await HostsFileEditor.DeleteEntryAsync(SelectedResult); + var result = await HostsFileEditor.DeleteEntryAsync(SelectedResult); - if (result != HostsFileEntryModifyResult.Success) - await ShowErrorMessageAsync(result); + if (result != HostsFileEntryModifyResult.Success) + await ShowErrorMessageAsync(result); - IsModifying = false; - }, _ => - { - childWindow.IsOpen = false; - ConfigurationManager.Current.IsChildWindowOpen = false; + IsModifying = false; + }, _ => + { + childWindow.IsOpen = false; + ConfigurationManager.Current.IsChildWindowOpen = false; - IsModifying = false; - }, - string.Format(Strings.DeleteHostsFileEntryMessage, SelectedResult.IPAddress, SelectedResult.Hostname, string.IsNullOrEmpty(SelectedResult.Comment) ? "" : $"# {SelectedResult.Comment}"), + IsModifying = false; + }, + string.Format(Strings.DeleteHostsFileEntryMessage, SelectedResult.IPAddress, SelectedResult.Hostname, + string.IsNullOrEmpty(SelectedResult.Comment) ? "" : $"# {SelectedResult.Comment}"), Strings.Delete ); @@ -447,11 +428,39 @@ private async Task DeleteEntryAction() private bool ModifyEntry_CanExecute(object obj) { return ConfigurationManager.Current.IsAdmin && - Application.Current.MainWindow != null && - !((MetroWindow)Application.Current.MainWindow).IsAnyDialogOpen && - !ConfigurationManager.Current.IsChildWindowOpen && - !IsRefreshing && - !IsModifying; + Application.Current.MainWindow != null && + !((MetroWindow)Application.Current.MainWindow).IsAnyDialogOpen && + !ConfigurationManager.Current.IsChildWindowOpen && + !IsRefreshing && + !IsModifying; + } + + private async Task ShowErrorMessageAsync(HostsFileEntryModifyResult result) + { + var message = result switch + { + HostsFileEntryModifyResult.ReadError => Strings.HostsFileReadErrorMessage, + HostsFileEntryModifyResult.WriteError => Strings.HostsFileWriteErrorMessage, + HostsFileEntryModifyResult.NotFound => Strings.HostsFileEntryNotFoundMessage, + HostsFileEntryModifyResult.BackupError => Strings.HostsFileBackupErrorMessage, + _ => Strings.UnkownError + }; + + var childWindow = new OKMessageChildWindow(); + + var childWindowViewModel = new OKMessageViewModel(_ => + { + childWindow.IsOpen = false; + ConfigurationManager.Current.IsChildWindowOpen = false; + }, message); + + childWindow.Title = Strings.Error; + + childWindow.DataContext = childWindowViewModel; + + ConfigurationManager.Current.IsChildWindowOpen = true; + + await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow); } public ICommand RestartAsAdminCommand => new RelayCommand(_ => RestartAsAdminAction().ConfigureAwait(false)); @@ -468,6 +477,7 @@ await _dialogCoordinator.ShowMessageAsync(this, Strings.Error, ex.Message, MessageDialogStyle.Affirmative, AppearanceManager.MetroDialog); } } + #endregion #region Methods @@ -509,7 +519,8 @@ private async Task Refresh(bool init = false) StatusMessage = string.Format(Strings.FailedToLoadHostsFileMessage, ex.Message); if (i < 3) - StatusMessage += Environment.NewLine + string.Format(Strings.RetryingInXSecondsDots, GlobalStaticConfiguration.ApplicationUIRefreshInterval / 1000); + StatusMessage += Environment.NewLine + string.Format(Strings.RetryingInXSecondsDots, + GlobalStaticConfiguration.ApplicationUIRefreshInterval / 1000); IsStatusMessageDisplayed = true; @@ -522,12 +533,11 @@ private async Task Refresh(bool init = false) public void OnViewVisible() { - } public void OnViewHide() { - } + #endregion } \ No newline at end of file diff --git a/Source/NETworkManager/log4net.config b/Source/NETworkManager/log4net.config index d149d6aae4..b3be9c74d0 100644 --- a/Source/NETworkManager/log4net.config +++ b/Source/NETworkManager/log4net.config @@ -1,8 +1,7 @@  - - + diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index ea18dc7533..c05a6d58db 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -23,7 +23,7 @@ Release date: **xx.xx.2025** **Hosts File Editor** -- New feature to display (and edit) the `hosts` file. (See [documentation](https://borntoberoot.net/NETworkManager/docs/application/hosts-file-editor) for more details) [#3012](https://github.com/BornToBeRoot/NETworkManager/pull/3012) [#3092](https://github.com/BornToBeRoot/NETworkManager/pull/3092) [#3094](https://github.com/BornToBeRoot/NETworkManager/pull/3094) [#3098](https://github.com/BornToBeRoot/NETworkManager/pull/3098) +- New feature to display (and edit) the `hosts` file. (See [documentation](https://borntoberoot.net/NETworkManager/docs/application/hosts-file-editor) for more details) [#3012](https://github.com/BornToBeRoot/NETworkManager/pull/3012) [#3092](https://github.com/BornToBeRoot/NETworkManager/pull/3092) [#3094](https://github.com/BornToBeRoot/NETworkManager/pull/3094) [#3098](https://github.com/BornToBeRoot/NETworkManager/pull/3098) [#3103](https://github.com/BornToBeRoot/NETworkManager/pull/3103) :::info