Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Source/NETworkManager.Localization/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3933,4 +3933,9 @@ Right-click for more options.</value>
<data name="Entries" xml:space="preserve">
<value>Entries</value>
</data>
<data name="DeleteHostsFileEntryMessage" xml:space="preserve">
<value>The selected entry is permanently deleted:

{0} {1} {2}</value>
</data>
</root>
132 changes: 120 additions & 12 deletions Source/NETworkManager.Models/HostsFileEditor/HostsFileEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,27 +164,52 @@ private static IEnumerable<HostsFileEntry> GetHostsFileEntries()
return entries;
}

public static Task<bool> EnableEntryAsync(HostsFileEntry entry)
/// <summary>
/// Enable a hosts file entry asynchronously.
/// </summary>
/// <param name="entry">Entry to enable.</param>
/// <returns><see cref="HostsFileEntryModifyResult.Success"/> if the entry was enabled successfully, otherwise an error result.</returns>
public static Task<HostsFileEntryModifyResult> EnableEntryAsync(HostsFileEntry entry)
{
return Task.Run(() => EnableEntry(entry));
}

private static bool EnableEntry(HostsFileEntry entry)
/// <summary>
/// Enable a hosts file entry.
/// </summary>
/// <param name="entry">Entry to enable.</param>
/// <returns><see cref="HostsFileEntryModifyResult.Success"/> if the entry was enabled successfully, otherwise an error result.</returns>
private static HostsFileEntryModifyResult EnableEntry(HostsFileEntry entry)
{
// Create a backup of the hosts file before making changes
if (CreateBackup() == false)
{
Log.Error("EnableEntry - Failed to create backup before enabling entry.");
return false;
return HostsFileEntryModifyResult.BackupError;
}

// Replace the entry in the hosts file
var hostsFileLines = File.ReadAllLines(HostsFilePath).ToList();

bool entryFound = false;

for (var i = 0; i < hostsFileLines.Count; i++)
{
if (hostsFileLines[i] == entry.Line)
{
entryFound = true;

hostsFileLines[i] = entry.Line.TrimStart('#', ' ');

break;
}
}

if (!entryFound)
{
Log.Warn($"EnableEntry - Entry not found in hosts file: {entry.Line}");

return HostsFileEntryModifyResult.NotFound;
}

try
Expand All @@ -195,34 +220,57 @@ private static bool EnableEntry(HostsFileEntry entry)
catch (Exception ex)
{
Log.Error($"EnableEntry - Failed to write changes to hosts file: {HostsFilePath}", ex);

return false;
return HostsFileEntryModifyResult.WriteError;
}

return true;
return HostsFileEntryModifyResult.Success;
}

public static Task<bool> DisableEntryAsync(HostsFileEntry entry)
/// <summary>
/// Disable a hosts file entry asynchronously.
/// </summary>
/// <param name="entry">Entry to disable.</param>
/// <returns><see cref="HostsFileEntryModifyResult.Success"/> if the entry was enabled successfully, otherwise an error result.</returns>
public static Task<HostsFileEntryModifyResult> DisableEntryAsync(HostsFileEntry entry)
{
return Task.Run(() => DisableEntry(entry));
}

private static bool DisableEntry(HostsFileEntry entry)
/// <summary>
/// Disable a hosts file entry.
/// </summary>
/// <param name="entry">Entry to disable.</param>
/// <returns><see cref="HostsFileEntryModifyResult.Success"/> if the entry was enabled successfully, otherwise an error result.</returns>
private static HostsFileEntryModifyResult DisableEntry(HostsFileEntry entry)
{
// Create a backup of the hosts file before making changes
if (CreateBackup() == false)
{
Log.Error("DisableEntry - Failed to create backup before disabling entry.");
return false;
return HostsFileEntryModifyResult.BackupError;
}

// Replace the entry in the hosts file
var hostsFileLines = File.ReadAllLines(HostsFilePath).ToList();

bool entryFound = false;

for (var i = 0; i < hostsFileLines.Count; i++)
{
if (hostsFileLines[i] == entry.Line)
{
entryFound = true;

hostsFileLines[i] = "# " + entry.Line;

break;
}
}

if (!entryFound)
{
Log.Warn($"DisableEntry - Entry not found in hosts file: {entry.Line}");
return HostsFileEntryModifyResult.NotFound;
}

try
Expand All @@ -233,15 +281,75 @@ private static bool DisableEntry(HostsFileEntry entry)
catch (Exception ex)
{
Log.Error($"DisableEntry - Failed to write changes to hosts file: {HostsFilePath}", ex);
return HostsFileEntryModifyResult.WriteError;
}

return false;
return HostsFileEntryModifyResult.Success;
}

/// <summary>
/// Delete a hosts file entry asynchronously.
/// </summary>
/// <param name="entry">Entry to delete.</param>"/>
/// <returns><see cref="HostsFileEntryModifyResult.Success"/> if the entry was enabled successfully, otherwise an error result.</returns>s
public static Task<HostsFileEntryModifyResult> DeleteEntryAsync(HostsFileEntry entry)
{
return Task.Run(() => DeleteEntry(entry));
}

/// <summary>
/// Delete a hosts file entry.
/// </summary>
/// <param name="entry">Entry to delete.</param>"/>
/// <returns><see cref="HostsFileEntryModifyResult.Success"/> if the entry was enabled successfully, otherwise an error result.</returns>
private static HostsFileEntryModifyResult DeleteEntry(HostsFileEntry entry)
{
// Create a backup of the hosts file before making changes
if (CreateBackup() == false)
{
Log.Error("DeleteEntry - Failed to create backup before deleting entry.");
return HostsFileEntryModifyResult.BackupError;
}

return true;
// Remove the entry from the hosts file
var hostsFileLines = File.ReadAllLines(HostsFilePath).ToList();

bool entryFound = false;

for (var i = 0; i < hostsFileLines.Count; i++)
{
if (hostsFileLines[i] == entry.Line)
{
entryFound = true;

hostsFileLines.RemoveAt(i);

break;
}
}

if (!entryFound)
{
Log.Warn($"DeleteEntry - Entry not found in hosts file: {entry.Line}");
return HostsFileEntryModifyResult.NotFound;
}

try
{
Log.Debug($"DeleteEntry - Writing changes to hosts file: {HostsFilePath}");
File.WriteAllLines(HostsFilePath, hostsFileLines);
}
catch (Exception ex)
{
Log.Error($"DeleteEntry - Failed to write changes to hosts file: {HostsFilePath}", ex);
return HostsFileEntryModifyResult.WriteError;
}
OnHostsFileChanged();
return HostsFileEntryModifyResult.Success;
}

/// <summary>
/// Create a daily backup of the hosts file (before making a change).
/// Create a "daily" backup of the hosts file (before making a change).
/// </summary>
private static bool CreateBackup()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace NETworkManager.Models.HostsFileEditor
{
/// <summary>
/// Represents the result of an attempt to modify a hosts file entry.
/// </summary>
public enum HostsFileEntryModifyResult
{
/// <summary>
/// The entry was modified successfully and the hosts file was updated.
/// </summary>
Success,

/// <summary>
/// The entry was not found in the hosts file.
/// </summary>
NotFound,

/// <summary>
/// An error occurred while writing to the hosts file.
/// </summary>
WriteError,

/// <summary>
/// An error occurred while backing up the hosts file.
/// </summary>
BackupError,
}
}
57 changes: 54 additions & 3 deletions Source/NETworkManager/ViewModels/HostsFileEditorViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ public IList SelectedResults
}
}

private bool _isModifying;

public bool IsModifying
{
get => _isModifying;
set
{
if (value == _isModifying)
return;

_isModifying = value;
OnPropertyChanged();
}
}

private bool _isRefreshing;

public bool IsRefreshing
Expand Down Expand Up @@ -192,7 +207,8 @@ private bool Refresh_CanExecute(object parameter)
return Application.Current.MainWindow != null &&
!((MetroWindow)Application.Current.MainWindow).IsAnyDialogOpen &&
!ConfigurationManager.Current.IsChildWindowOpen &&
!IsRefreshing;
!IsRefreshing &&
!IsModifying;
}

private async Task RefreshAction()
Expand Down Expand Up @@ -253,14 +269,22 @@ await _dialogCoordinator.ShowMessageAsync(this, Strings.Error,

private async Task EnableEntryAction()
{
IsModifying = true;

await HostsFileEditor.EnableEntryAsync(SelectedResult);

IsModifying = false;
}

public ICommand DisableEntryCommand => new RelayCommand(_ => DisableEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute);

private async Task DisableEntryAction()
{
IsModifying = true;

await HostsFileEditor.DisableEntryAsync(SelectedResult);

IsModifying = false;
}

public ICommand AddEntryCommand => new RelayCommand(_ => AddEntryAction().ConfigureAwait(false), ModifyEntry_CanExecute);
Expand All @@ -274,7 +298,33 @@ private async Task AddEntryAction()

private async Task DeleteEntryAction()
{
MessageBox.Show("Delete entry action is not implemented yet.", "Delete Entry", MessageBoxButton.OK, MessageBoxImage.Information);
IsModifying = true;

var childWindow = new OKCancelInfoMessageChildWindow();

var childWindowViewModel = new OKCancelInfoMessageViewModel(async _ =>
{
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;

await HostsFileEditor.DeleteEntryAsync(SelectedResult);

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}"));

childWindow.Title = Strings.DeleteEntry;

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);
Expand All @@ -290,7 +340,8 @@ private bool ModifyEntry_CanExecute(object obj)
Application.Current.MainWindow != null &&
!((MetroWindow)Application.Current.MainWindow).IsAnyDialogOpen &&
!ConfigurationManager.Current.IsChildWindowOpen &&
!IsRefreshing;
!IsRefreshing &&
!IsModifying;
}

public ICommand RestartAsAdminCommand => new RelayCommand(_ => RestartAsAdminAction().ConfigureAwait(false));
Expand Down
17 changes: 8 additions & 9 deletions Source/NETworkManager/ViewModels/SNTPLookupSettingsViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using MahApps.Metro.Controls.Dialogs;
using MahApps.Metro.Controls.Dialogs;
using MahApps.Metro.SimpleChildWindow;
using NETworkManager.Localization.Resources;
using NETworkManager.Models.Network;
using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace NETworkManager.ViewModels;

Expand Down Expand Up @@ -189,7 +189,6 @@ private Task DeleteServer()
{
var childWindow = new OKCancelInfoMessageChildWindow();


var childWindowViewModel = new OKCancelInfoMessageViewModel(_ =>
{
childWindow.IsOpen = false;
Expand Down
2 changes: 1 addition & 1 deletion Source/NETworkManager/Views/ExportChildWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="10" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
Expand Down
Loading