HostsViewModel.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Runtime.CompilerServices; 7 using System.Threading; 8 using global::PowerToys.GPOWrapper; 9 using Microsoft.PowerToys.Settings.UI.Helpers; 10 using Microsoft.PowerToys.Settings.UI.Library; 11 using Microsoft.PowerToys.Settings.UI.Library.Helpers; 12 using Microsoft.PowerToys.Settings.UI.Library.Interfaces; 13 using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands; 14 using PowerToys.Interop; 15 using Settings.UI.Library.Enumerations; 16 17 namespace Microsoft.PowerToys.Settings.UI.ViewModels 18 { 19 public partial class HostsViewModel : Observable 20 { 21 private bool _isElevated; 22 private GpoRuleConfigured _enabledGpoRuleConfiguration; 23 private bool _enabledStateIsGPOConfigured; 24 private bool _isEnabled; 25 26 private SettingsUtils SettingsUtils { get; set; } 27 28 private GeneralSettings GeneralSettingsConfig { get; set; } 29 30 private HostsSettings Settings { get; set; } 31 32 private Func<string, int> SendConfigMSG { get; } 33 34 public ButtonClickCommand LaunchEventHandler => new ButtonClickCommand(Launch); 35 36 public ButtonClickCommand SelectBackupPathEventHandler => new ButtonClickCommand(SelectBackupPath); 37 38 public bool IsEnabled 39 { 40 get => _isEnabled; 41 42 set 43 { 44 if (_enabledStateIsGPOConfigured) 45 { 46 // If it's GPO configured, shouldn't be able to change this state. 47 return; 48 } 49 50 if (value != _isEnabled) 51 { 52 _isEnabled = value; 53 54 // Set the status in the general settings configuration 55 GeneralSettingsConfig.Enabled.Hosts = value; 56 OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig); 57 58 SendConfigMSG(snd.ToString()); 59 OnPropertyChanged(nameof(IsEnabled)); 60 } 61 } 62 } 63 64 public bool IsEnabledGpoConfigured 65 { 66 get => _enabledStateIsGPOConfigured; 67 } 68 69 public bool LaunchAdministratorEnabled => IsEnabled && !_isElevated; 70 71 public bool ShowStartupWarning 72 { 73 get => Settings.Properties.ShowStartupWarning; 74 set 75 { 76 if (value != Settings.Properties.ShowStartupWarning) 77 { 78 Settings.Properties.ShowStartupWarning = value; 79 NotifyPropertyChanged(); 80 } 81 } 82 } 83 84 public bool LoopbackDuplicates 85 { 86 get => Settings.Properties.LoopbackDuplicates; 87 set 88 { 89 if (value != Settings.Properties.LoopbackDuplicates) 90 { 91 Settings.Properties.LoopbackDuplicates = value; 92 NotifyPropertyChanged(); 93 } 94 } 95 } 96 97 public bool LaunchAdministrator 98 { 99 get => Settings.Properties.LaunchAdministrator; 100 set 101 { 102 if (value != Settings.Properties.LaunchAdministrator) 103 { 104 Settings.Properties.LaunchAdministrator = value; 105 NotifyPropertyChanged(); 106 } 107 } 108 } 109 110 public bool NoLeadingSpaces 111 { 112 get => Settings.Properties.NoLeadingSpaces; 113 set 114 { 115 if (value != Settings.Properties.NoLeadingSpaces) 116 { 117 Settings.Properties.NoLeadingSpaces = value; 118 NotifyPropertyChanged(); 119 } 120 } 121 } 122 123 public int AdditionalLinesPosition 124 { 125 get => (int)Settings.Properties.AdditionalLinesPosition; 126 set 127 { 128 if (value != (int)Settings.Properties.AdditionalLinesPosition) 129 { 130 Settings.Properties.AdditionalLinesPosition = (HostsAdditionalLinesPosition)value; 131 NotifyPropertyChanged(); 132 } 133 } 134 } 135 136 public int Encoding 137 { 138 get => (int)Settings.Properties.Encoding; 139 set 140 { 141 if (value != (int)Settings.Properties.Encoding) 142 { 143 Settings.Properties.Encoding = (HostsEncoding)value; 144 NotifyPropertyChanged(); 145 } 146 } 147 } 148 149 public bool BackupHosts 150 { 151 get => Settings.Properties.BackupHosts; 152 set 153 { 154 if (value != Settings.Properties.BackupHosts) 155 { 156 Settings.Properties.BackupHosts = value; 157 NotifyPropertyChanged(); 158 } 159 } 160 } 161 162 public string BackupPath 163 { 164 get => Settings.Properties.BackupPath; 165 set 166 { 167 if (value != Settings.Properties.BackupPath) 168 { 169 Settings.Properties.BackupPath = value; 170 NotifyPropertyChanged(); 171 } 172 } 173 } 174 175 public int DeleteBackupsMode 176 { 177 get => (int)Settings.Properties.DeleteBackupsMode; 178 set 179 { 180 if (value != (int)Settings.Properties.DeleteBackupsMode) 181 { 182 Settings.Properties.DeleteBackupsMode = (HostsDeleteBackupMode)value; 183 NotifyPropertyChanged(); 184 OnPropertyChanged(nameof(MinimumBackupsCount)); 185 } 186 } 187 } 188 189 public int DeleteBackupsDays 190 { 191 get => Settings.Properties.DeleteBackupsDays; 192 set 193 { 194 if (value != Settings.Properties.DeleteBackupsDays) 195 { 196 Settings.Properties.DeleteBackupsDays = value; 197 NotifyPropertyChanged(); 198 } 199 } 200 } 201 202 public int DeleteBackupsCount 203 { 204 get => Settings.Properties.DeleteBackupsCount; 205 set 206 { 207 if (value != Settings.Properties.DeleteBackupsCount) 208 { 209 Settings.Properties.DeleteBackupsCount = value; 210 NotifyPropertyChanged(); 211 } 212 } 213 } 214 215 public int MinimumBackupsCount => DeleteBackupsMode == 1 ? 1 : 0; 216 217 public HostsViewModel(SettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<HostsSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, bool isElevated) 218 { 219 SettingsUtils = settingsUtils; 220 GeneralSettingsConfig = settingsRepository.SettingsConfig; 221 Settings = moduleSettingsRepository.SettingsConfig; 222 SendConfigMSG = ipcMSGCallBackFunc; 223 _isElevated = isElevated; 224 InitializeEnabledValue(); 225 } 226 227 private void InitializeEnabledValue() 228 { 229 _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredHostsFileEditorEnabledValue(); 230 if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) 231 { 232 // Get the enabled state from GPO. 233 _enabledStateIsGPOConfigured = true; 234 _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; 235 } 236 else 237 { 238 _isEnabled = GeneralSettingsConfig.Enabled.Hosts; 239 } 240 } 241 242 public void Launch() 243 { 244 string eventName = !_isElevated && LaunchAdministrator 245 ? Constants.ShowHostsAdminSharedEvent() 246 : Constants.ShowHostsSharedEvent(); 247 248 using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName)) 249 { 250 eventHandle.Set(); 251 } 252 } 253 254 public void NotifyPropertyChanged([CallerMemberName] string propertyName = null) 255 { 256 OnPropertyChanged(propertyName); 257 SettingsUtils.SaveSettings(Settings.ToJsonString(), HostsSettings.ModuleName); 258 } 259 260 public void RefreshEnabledState() 261 { 262 InitializeEnabledValue(); 263 OnPropertyChanged(nameof(IsEnabled)); 264 } 265 266 public void SelectBackupPath() 267 { 268 // This function was changed to use the shell32 API to open folder dialog 269 // as the old one (PickSingleFolderAsync) can't work when the process is elevated 270 // TODO: go back PickSingleFolderAsync when it's fixed 271 var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.GetSettingsWindow()); 272 var result = ShellGetFolder.GetFolderDialog(hwnd); 273 if (!string.IsNullOrEmpty(result)) 274 { 275 BackupPath = result; 276 } 277 } 278 } 279 }