/ src / settings-ui / Settings.UI / ViewModels / HostsViewModel.cs
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  }