Winify – Diff between revs 73 and 75

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 73 Rev 75
1 using System; 1 using System;
2 using System.Collections.Concurrent; 2 using System.Collections.Concurrent;
3 using System.ComponentModel; 3 using System.ComponentModel;
4 using System.Drawing; 4 using System.Drawing;
5 using System.IO; 5 using System.IO;
6 using System.Net; 6 using System.Net;
7 using System.Reflection; 7 using System.Reflection;
8 using System.Text; 8 using System.Text;
9 using System.Threading; 9 using System.Threading;
10 using System.Threading.Tasks; 10 using System.Threading.Tasks;
11 using System.Windows.Forms; 11 using System.Windows.Forms;
12 using NetSparkleUpdater; 12 using NetSparkleUpdater;
13 using NetSparkleUpdater.Enums; 13 using NetSparkleUpdater.Enums;
14 using NetSparkleUpdater.SignatureVerifiers; 14 using NetSparkleUpdater.SignatureVerifiers;
15 using NetSparkleUpdater.UI.WinForms; 15 using NetSparkleUpdater.UI.WinForms;
16 using Serilog; 16 using Serilog;
17 using Servers; 17 using Servers;
18 using Toasts; 18 using Toasts;
19 using Winify.Gotify; 19 using Winify.Gotify;
20 using Winify.Settings; 20 using Winify.Settings;
21 using Winify.Utilities; 21 using Winify.Utilities;
22 using Winify.Utilities.Serialization; 22 using Winify.Utilities.Serialization;
23 using ScheduledContinuation = Toasts.ScheduledContinuation; 23 using ScheduledContinuation = Toasts.ScheduledContinuation;
24   24  
25 namespace Winify 25 namespace Winify
26 { 26 {
27 public partial class MainForm : Form 27 public partial class MainForm : Form
28 { 28 {
29 #region Public Enums, Properties and Fields 29 #region Public Enums, Properties and Fields
30   30  
31 public Configuration.Configuration Configuration { get; set; } 31 public Configuration.Configuration Configuration { get; set; }
32   32  
33 public ScheduledContinuation ChangedConfigurationContinuation { get; set; } 33 public ScheduledContinuation ChangedConfigurationContinuation { get; set; }
34   34  
35 public bool MemorySinkEnabled { get; set; } 35 public bool MemorySinkEnabled { get; set; }
36   36  
37 #endregion 37 #endregion
38   38  
39 #region Private Delegates, Events, Enums, Properties, Indexers and Fields 39 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
40   40  
41 private AboutForm _aboutForm; 41 private AboutForm _aboutForm;
42   42  
43 private ConcurrentBag<GotifyConnection> _gotifyConnections; 43 private ConcurrentBag<GotifyConnection> _gotifyConnections;
44   44  
45 private SettingsForm _settingsForm; 45 private SettingsForm _settingsForm;
46   46  
47 private readonly SparkleUpdater _sparkle; 47 private readonly SparkleUpdater _sparkle;
48   48  
49 private readonly CancellationTokenSource _cancellationTokenSource; 49 private readonly CancellationTokenSource _cancellationTokenSource;
50   50  
51 private readonly CancellationToken _cancellationToken; 51 private readonly CancellationToken _cancellationToken;
52   52  
53 private LogViewForm _logViewForm; 53 private LogViewForm _logViewForm;
54   54  
55 private readonly LogMemorySink _memorySink; 55 private readonly LogMemorySink _memorySink;
56   56  
57 private readonly Toasts.Toasts _toasts; 57 private readonly Toasts.Toasts _toasts;
58   58  
59 #endregion 59 #endregion
60   60  
61 #region Constructors, Destructors and Finalizers 61 #region Constructors, Destructors and Finalizers
62   62  
63 public MainForm() 63 public MainForm()
64 { 64 {
65 InitializeComponent(); 65 InitializeComponent();
66   66  
67 _cancellationTokenSource = new CancellationTokenSource(); 67 _cancellationTokenSource = new CancellationTokenSource();
68 _cancellationToken = _cancellationTokenSource.Token; 68 _cancellationToken = _cancellationTokenSource.Token;
69   69  
70 ChangedConfigurationContinuation = new ScheduledContinuation(); 70 ChangedConfigurationContinuation = new ScheduledContinuation();
71   71  
72 _toasts = new Toasts.Toasts(_cancellationToken); 72 _toasts = new Toasts.Toasts(_cancellationToken);
73 } 73 }
74   74  
75 public MainForm(Mutex mutex) : this() 75 public MainForm(Mutex mutex) : this()
76 { 76 {
77 _memorySink = new LogMemorySink(); 77 _memorySink = new LogMemorySink();
78 Log.Logger = new LoggerConfiguration() 78 Log.Logger = new LoggerConfiguration()
79 .MinimumLevel.Debug() 79 .MinimumLevel.Debug()
80 .WriteTo.Conditional(condition => MemorySinkEnabled, configureSink => configureSink.Sink(_memorySink)) 80 .WriteTo.Conditional(condition => MemorySinkEnabled, configureSink => configureSink.Sink(_memorySink))
81 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"), 81 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"),
82 rollingInterval: RollingInterval.Day) 82 rollingInterval: RollingInterval.Day)
83 .CreateLogger(); 83 .CreateLogger();
84   84  
85 // Start application update. 85 // Start application update.
86 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName; 86 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
87 var icon = Icon.ExtractAssociatedIcon(manifestModuleName); 87 var icon = Icon.ExtractAssociatedIcon(manifestModuleName);
88   88  
89 _sparkle = new SparkleUpdater("https://winify.grimore.org/update/appcast.xml", 89 _sparkle = new SparkleUpdater("https://winify.grimore.org/update/appcast.xml",
90 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY=")) 90 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
91 { 91 {
92 UIFactory = new UIFactory(icon), 92 UIFactory = new UIFactory(icon),
93 RelaunchAfterUpdate = true, 93 RelaunchAfterUpdate = true,
94 SecurityProtocolType = SecurityProtocolType.Tls12 94 SecurityProtocolType = SecurityProtocolType.Tls12
95 }; 95 };
96 _sparkle.StartLoop(true, true); 96 _sparkle.StartLoop(true, true);
97 } 97 }
98   98  
99 /// <summary> 99 /// <summary>
100 /// Clean up any resources being used. 100 /// Clean up any resources being used.
101 /// </summary> 101 /// </summary>
102 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 102 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
103 protected override void Dispose(bool disposing) 103 protected override void Dispose(bool disposing)
104 { 104 {
105 if (disposing && components != null) components.Dispose(); 105 if (disposing && components != null) components.Dispose();
106   106  
107 base.Dispose(disposing); 107 base.Dispose(disposing);
108 } 108 }
109   109  
110 #endregion 110 #endregion
111   111  
112 #region Event Handlers 112 #region Event Handlers
113   113  
114 private async void MainForm_Load(object sender, EventArgs e) 114 private async void MainForm_Load(object sender, EventArgs e)
115 { 115 {
116 Configuration = await LoadConfiguration(); 116 Configuration = await LoadConfiguration();
117   117  
118 var servers = await LoadServers(); 118 var servers = await LoadServers();
119 _gotifyConnections = new ConcurrentBag<GotifyConnection>(); 119 _gotifyConnections = new ConcurrentBag<GotifyConnection>();
120 foreach (var server in servers.Server) 120 foreach (var server in servers.Server)
121 { 121 {
122 var gotifyConnection = new GotifyConnection(server, Configuration); 122 var gotifyConnection = new GotifyConnection(server, Configuration);
123 gotifyConnection.GotifyMessage += GotifyConnectionGotifyMessage; 123 gotifyConnection.GotifyMessage += GotifyConnectionGotifyMessage;
124 gotifyConnection.Start(); 124 gotifyConnection.Start();
125 _gotifyConnections.Add(gotifyConnection); 125 _gotifyConnections.Add(gotifyConnection);
126 } 126 }
127 } 127 }
128   128  
129 private void LogViewToolStripMenuItem_Click(object sender, EventArgs e) 129 private void LogViewToolStripMenuItem_Click(object sender, EventArgs e)
130 { 130 {
131 if (_logViewForm != null) 131 if (_logViewForm != null)
132 { 132 {
133 return; 133 return;
134 } 134 }
135   135  
136 _logViewForm = new LogViewForm(this, _memorySink, _cancellationToken); 136 _logViewForm = new LogViewForm(this, _memorySink, _cancellationToken);
137 _logViewForm.Closing += LogViewForm_Closing; 137 _logViewForm.Closing += LogViewForm_Closing;
138 _logViewForm.Show(); 138 _logViewForm.Show();
139 } 139 }
140   140  
141 private void LogViewForm_Closing(object sender, CancelEventArgs e) 141 private void LogViewForm_Closing(object sender, CancelEventArgs e)
142 { 142 {
143 if (_logViewForm == null) 143 if (_logViewForm == null)
144 { 144 {
145 return; 145 return;
146 } 146 }
147   147  
148 _logViewForm.Closing -= LogViewForm_Closing; 148 _logViewForm.Closing -= LogViewForm_Closing;
149 _logViewForm.Close(); 149 _logViewForm.Close();
150 _logViewForm = null; 150 _logViewForm = null;
151 } 151 }
152   152  
153 private async void SettingsToolStripMenuItem_Click(object sender, EventArgs e) 153 private async void SettingsToolStripMenuItem_Click(object sender, EventArgs e)
154 { 154 {
155 if (_settingsForm == null) 155 if (_settingsForm == null)
156 { 156 {
157 var servers = await LoadServers(); 157 var servers = await LoadServers();
158 var announcements = await LoadAnnouncements(); 158 var announcements = await LoadAnnouncements();
159   159  
160 _settingsForm = new SettingsForm(this, servers, announcements, _cancellationToken); 160 _settingsForm = new SettingsForm(this, servers, announcements, _cancellationToken);
161 _settingsForm.Save += SettingsForm_Save; 161 _settingsForm.Save += SettingsForm_Save;
162 _settingsForm.Closing += SettingsForm_Closing; 162 _settingsForm.Closing += SettingsForm_Closing;
163 _settingsForm.Show(); 163 _settingsForm.Show();
164 } 164 }
165 } 165 }
166   166  
167 private async void SettingsForm_Save(object sender, SettingsSavedEventArgs e) 167 private async void SettingsForm_Save(object sender, SettingsSavedEventArgs e)
168 { 168 {
169 // Save the configuration. 169 // Save the configuration.
170 Miscellaneous.LaunchOnBootSet(Configuration.LaunchOnBoot); 170 Miscellaneous.LaunchOnBootSet(Configuration.LaunchOnBoot);
171 ChangedConfigurationContinuation.Schedule(TimeSpan.FromSeconds(1), 171 ChangedConfigurationContinuation.Schedule(TimeSpan.FromSeconds(1),
172 async () => { await SaveConfiguration(); }, _cancellationToken); 172 async () => { await SaveConfiguration(); }, _cancellationToken);
173   173  
174 // Save the servers. 174 // Save the servers.
175 await Task.WhenAll(SaveServers(e.Servers), SaveAnnouncements(e.Announcements)); 175 await Task.WhenAll(SaveServers(e.Servers), SaveAnnouncements(e.Announcements));
176   176  
177 // Update connections to gotify servers. 177 // Update connections to gotify servers.
178 while (_gotifyConnections.TryTake(out var gotifyConnection)) 178 while (_gotifyConnections.TryTake(out var gotifyConnection))
179 { 179 {
180 gotifyConnection.GotifyMessage -= GotifyConnectionGotifyMessage; 180 gotifyConnection.GotifyMessage -= GotifyConnectionGotifyMessage;
181 await gotifyConnection.Stop(); 181 await gotifyConnection.Stop();
182 gotifyConnection.Dispose(); 182 gotifyConnection.Dispose();
183 } 183 }
184   184  
185 foreach (var server in e.Servers.Server) 185 foreach (var server in e.Servers.Server)
186 { 186 {
187 var gotifyConnection = new GotifyConnection(server, Configuration); 187 var gotifyConnection = new GotifyConnection(server, Configuration);
188 gotifyConnection.GotifyMessage += GotifyConnectionGotifyMessage; 188 gotifyConnection.GotifyMessage += GotifyConnectionGotifyMessage;
189 gotifyConnection.Start(); 189 gotifyConnection.Start();
190 _gotifyConnections.Add(gotifyConnection); 190 _gotifyConnections.Add(gotifyConnection);
191 } 191 }
192 } 192 }
193   193  
194 private async void GotifyConnectionGotifyMessage(object sender, GotifyMessageEventArgs e) 194 private async void GotifyConnectionGotifyMessage(object sender, GotifyMessageEventArgs e)
195 { 195 {
196 var announcements = await LoadAnnouncements(); 196 var announcements = await LoadAnnouncements();
197   197  
198 foreach (var announcement in announcements.Announcement) 198 foreach (var announcement in announcements.Announcement)
199 { 199 {
200 if (announcement.AppId != e.Message.AppId) 200 if (announcement.AppId != e.Message.AppId)
201 { 201 {
202 continue; 202 continue;
203 } 203 }
204   204  
205 if (announcement.Ignore) 205 if (announcement.Ignore)
206 { 206 {
207 return; 207 return;
208 } 208 }
209   209  
210 if (announcement.LingerTime <= 0) 210 if (announcement.LingerTime <= 0)
211 { 211 {
212 return; 212 return;
213 } 213 }
214   214  
215 var configuredNotification = new ToastForm( 215 var configuredNotification = new ToastForm(
216 $"{e.Message.Title} ({e.Message.Server.Name}/{e.Message.AppId})", 216 $"{e.Message.Title} ({e.Message.Server.Name}/{e.Message.AppId})",
217 e.Message.Message) 217 e.Message.Message)
218 { 218 {
219 EnableChime = announcement.EnableChime, 219 EnableChime = announcement.EnableChime,
-   220 Chime = announcement.Chime ?? Configuration.Chime,
220 LingerTime = (int)announcement.LingerTime, 221 LingerTime = (int)announcement.LingerTime,
221 Image = e.Image 222 Image = e.Image
222 }; 223 };
223   224  
224 await _toasts.Queue(configuredNotification); 225 await _toasts.Queue(configuredNotification);
225   226  
226 return; 227 return;
227 } 228 }
228   229  
229 if (Configuration.InfiniteToastDuration) 230 if (Configuration.InfiniteToastDuration)
230 { 231 {
231 var infiniteToastForm = new ToastForm( 232 var infiniteToastForm = new ToastForm(
232 $"{e.Message.Title} ({e.Message.Server.Name}/{e.Message.AppId})", 233 $"{e.Message.Title} ({e.Message.Server.Name}/{e.Message.AppId})",
233 e.Message.Message) 234 e.Message.Message)
234 { 235 {
-   236 Chime = Configuration.Chime,
235 Image = e.Image 237 Image = e.Image
236 }; 238 };
237   239  
238 await _toasts.Queue(infiniteToastForm); 240 await _toasts.Queue(infiniteToastForm);
239   241  
240 return; 242 return;
241 } 243 }
242   244  
243 var toastForm = new ToastForm( 245 var toastForm = new ToastForm(
244 $"{e.Message.Title} ({e.Message.Server.Name}/{e.Message.AppId})", 246 $"{e.Message.Title} ({e.Message.Server.Name}/{e.Message.AppId})",
245 e.Message.Message) 247 e.Message.Message)
246 { 248 {
-   249 Chime = Configuration.Chime,
247 LingerTime = Configuration.ToastDuration, 250 LingerTime = Configuration.ToastDuration,
248 Image = e.Image 251 Image = e.Image
249 }; 252 };
250   253  
251 await _toasts.Queue(toastForm); 254 await _toasts.Queue(toastForm);
252 } 255 }
253   256  
254 private void SettingsForm_Closing(object sender, CancelEventArgs e) 257 private void SettingsForm_Closing(object sender, CancelEventArgs e)
255 { 258 {
256 if (_settingsForm == null) 259 if (_settingsForm == null)
257 { 260 {
258 return; 261 return;
259 } 262 }
260   263  
261 _settingsForm.Save -= SettingsForm_Save; 264 _settingsForm.Save -= SettingsForm_Save;
262 _settingsForm.Closing -= SettingsForm_Closing; 265 _settingsForm.Closing -= SettingsForm_Closing;
263 _settingsForm.Dispose(); 266 _settingsForm.Dispose();
264 _settingsForm = null; 267 _settingsForm = null;
265 } 268 }
266   269  
267 private void AboutToolStripMenuItem_Click(object sender, EventArgs e) 270 private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
268 { 271 {
269 if (_aboutForm != null) 272 if (_aboutForm != null)
270 { 273 {
271 return; 274 return;
272 } 275 }
273   276  
274 _aboutForm = new AboutForm(); 277 _aboutForm = new AboutForm();
275 _aboutForm.Closing += AboutForm_Closing; 278 _aboutForm.Closing += AboutForm_Closing;
276 _aboutForm.Show(); 279 _aboutForm.Show();
277 } 280 }
278   281  
279 private void AboutForm_Closing(object sender, CancelEventArgs e) 282 private void AboutForm_Closing(object sender, CancelEventArgs e)
280 { 283 {
281 if (_aboutForm == null) 284 if (_aboutForm == null)
282 { 285 {
283 return; 286 return;
284 } 287 }
285   288  
286 _aboutForm.Closing -= AboutForm_Closing; 289 _aboutForm.Closing -= AboutForm_Closing;
287 _aboutForm.Dispose(); 290 _aboutForm.Dispose();
288 _aboutForm = null; 291 _aboutForm = null;
289 } 292 }
290   293  
291 private void QuitToolStripMenuItem_Click(object sender, EventArgs e) 294 private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
292 { 295 {
293 Close(); 296 Close();
294 } 297 }
295   298  
296 private async void UpdateToolStripMenuItem_Click(object sender, EventArgs e) 299 private async void UpdateToolStripMenuItem_Click(object sender, EventArgs e)
297 { 300 {
298 // Manually check for updates, this will not show a ui 301 // Manually check for updates, this will not show a ui
299 var result = await _sparkle.CheckForUpdatesQuietly(); 302 var result = await _sparkle.CheckForUpdatesQuietly();
300 var updates = result.Updates; 303 var updates = result.Updates;
301 if (result.Status == UpdateStatus.UpdateAvailable) 304 if (result.Status == UpdateStatus.UpdateAvailable)
302 { 305 {
303 // if update(s) are found, then we have to trigger the UI to show it gracefully 306 // if update(s) are found, then we have to trigger the UI to show it gracefully
304 _sparkle.ShowUpdateNeededUI(); 307 _sparkle.ShowUpdateNeededUI();
305 return; 308 return;
306 } 309 }
307   310  
308 MessageBox.Show("No updates available at this time.", "Winify", MessageBoxButtons.OK, 311 MessageBox.Show("No updates available at this time.", "Winify", MessageBoxButtons.OK,
309 MessageBoxIcon.Asterisk, 312 MessageBoxIcon.Asterisk,
310 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false); 313 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
311 } 314 }
312   315  
313 #endregion 316 #endregion
314   317  
315 #region Public Methods 318 #region Public Methods
316   319  
317 public async Task SaveConfiguration() 320 public async Task SaveConfiguration()
318 { 321 {
319 if (!Directory.Exists(Constants.UserApplicationDirectory)) 322 if (!Directory.Exists(Constants.UserApplicationDirectory))
320 Directory.CreateDirectory(Constants.UserApplicationDirectory); 323 Directory.CreateDirectory(Constants.UserApplicationDirectory);
321   324  
322 switch (await Serialization.Serialize(Configuration, Constants.ConfigurationFile, "Configuration", 325 switch (await Serialization.Serialize(Configuration, Constants.ConfigurationFile, "Configuration",
323 "<!ATTLIST Configuration xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>", 326 "<!ATTLIST Configuration xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
324 CancellationToken.None)) 327 CancellationToken.None))
325 { 328 {
326 case SerializationSuccess<Configuration.Configuration> _: 329 case SerializationSuccess<Configuration.Configuration> _:
327 Log.Information("Serialized configuration."); 330 Log.Information("Serialized configuration.");
328 break; 331 break;
329 case SerializationFailure serializationFailure: 332 case SerializationFailure serializationFailure:
330 Log.Warning(serializationFailure.Exception.Message, "Failed to serialize configuration."); 333 Log.Warning(serializationFailure.Exception.Message, "Failed to serialize configuration.");
331 break; 334 break;
332 } 335 }
333 } 336 }
334   337  
335 public static async Task<Configuration.Configuration> LoadConfiguration() 338 public static async Task<Configuration.Configuration> LoadConfiguration()
336 { 339 {
337 if (!Directory.Exists(Constants.UserApplicationDirectory)) 340 if (!Directory.Exists(Constants.UserApplicationDirectory))
338 Directory.CreateDirectory(Constants.UserApplicationDirectory); 341 Directory.CreateDirectory(Constants.UserApplicationDirectory);
339   342  
340 var deserializationResult = 343 var deserializationResult =
341 await Serialization.Deserialize<Configuration.Configuration>(Constants.ConfigurationFile, 344 await Serialization.Deserialize<Configuration.Configuration>(Constants.ConfigurationFile,
342 Constants.ConfigurationNamespace, Constants.ConfigurationXsd, CancellationToken.None); 345 Constants.ConfigurationNamespace, Constants.ConfigurationXsd, CancellationToken.None);
343   346  
344 switch (deserializationResult) 347 switch (deserializationResult)
345 { 348 {
346 case SerializationSuccess<Configuration.Configuration> serializationSuccess: 349 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
347 return serializationSuccess.Result; 350 return serializationSuccess.Result;
348 case SerializationFailure serializationFailure: 351 case SerializationFailure serializationFailure:
349 Log.Warning(serializationFailure.Exception, "Failed to load configuration."); 352 Log.Warning(serializationFailure.Exception, "Failed to load configuration.");
350 return new Configuration.Configuration(); 353 return new Configuration.Configuration();
351 default: 354 default:
352 return new Configuration.Configuration(); 355 return new Configuration.Configuration();
353 } 356 }
354 } 357 }
355   358  
356 #endregion 359 #endregion
357   360  
358 #region Private Methods 361 #region Private Methods
359   362  
360 private static async Task SaveAnnouncements(Announcements.Announcements announcements) 363 private static async Task SaveAnnouncements(Announcements.Announcements announcements)
361 { 364 {
362 switch (await Serialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements", 365 switch (await Serialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements",
363 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>", 366 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
364 CancellationToken.None)) 367 CancellationToken.None))
365 { 368 {
366 case SerializationFailure serializationFailure: 369 case SerializationFailure serializationFailure:
367 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements."); 370 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements.");
368 break; 371 break;
369 } 372 }
370 } 373 }
371   374  
372 private static async Task SaveServers(Servers.Servers servers) 375 private static async Task SaveServers(Servers.Servers servers)
373 { 376 {
374 // Encrypt password for all servers. 377 // Encrypt password for all servers.
375 var deviceId = Miscellaneous.GetMachineGuid(); 378 var deviceId = Miscellaneous.GetMachineGuid();
376 var @protected = new Servers.Servers 379 var @protected = new Servers.Servers
377 { 380 {
378 Server = new BindingListWithCollectionChanged<Server>() 381 Server = new BindingListWithCollectionChanged<Server>()
379 }; 382 };
380   383  
381 foreach (var server in servers.Server) 384 foreach (var server in servers.Server)
382 { 385 {
383 var password = Encoding.UTF8.GetBytes(server.Password); 386 var password = Encoding.UTF8.GetBytes(server.Password);
384 var encrypted = await AES.Encrypt(password, deviceId); 387 var encrypted = await AES.Encrypt(password, deviceId);
385 var armored = Convert.ToBase64String(encrypted); 388 var armored = Convert.ToBase64String(encrypted);
386   389  
387 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored)); 390 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored));
388 } 391 }
389   392  
390 switch (await Serialization.Serialize(@protected, Constants.ServersFile, "Servers", 393 switch (await Serialization.Serialize(@protected, Constants.ServersFile, "Servers",
391 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>", 394 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
392 CancellationToken.None)) 395 CancellationToken.None))
393 { 396 {
394 case SerializationFailure serializationFailure: 397 case SerializationFailure serializationFailure:
395 Log.Warning(serializationFailure.Exception, "Unable to serialize servers."); 398 Log.Warning(serializationFailure.Exception, "Unable to serialize servers.");
396 break; 399 break;
397 } 400 }
398 } 401 }
399   402  
400 private static async Task<Announcements.Announcements> LoadAnnouncements() 403 private static async Task<Announcements.Announcements> LoadAnnouncements()
401 { 404 {
402 if (!Directory.Exists(Constants.UserApplicationDirectory)) 405 if (!Directory.Exists(Constants.UserApplicationDirectory))
403 Directory.CreateDirectory(Constants.UserApplicationDirectory); 406 Directory.CreateDirectory(Constants.UserApplicationDirectory);
404   407  
405 var deserializationResult = 408 var deserializationResult =
406 await Serialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile, 409 await Serialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile,
407 "urn:winify-announcements-schema", "Announcements.xsd", CancellationToken.None); 410 "urn:winify-announcements-schema", "Announcements.xsd", CancellationToken.None);
408   411  
409 switch (deserializationResult) 412 switch (deserializationResult)
410 { 413 {
411 case SerializationSuccess<Announcements.Announcements> serializationSuccess: 414 case SerializationSuccess<Announcements.Announcements> serializationSuccess:
412 return serializationSuccess.Result; 415 return serializationSuccess.Result;
413 case SerializationFailure serializationFailure: 416 case SerializationFailure serializationFailure:
414 Log.Warning(serializationFailure.Exception, "Unable to load announcements."); 417 Log.Warning(serializationFailure.Exception, "Unable to load announcements.");
415 return new Announcements.Announcements(); 418 return new Announcements.Announcements();
416 default: 419 default:
417 return new Announcements.Announcements(); 420 return new Announcements.Announcements();
418 } 421 }
419 } 422 }
420   423  
421 private static async Task<Servers.Servers> LoadServers() 424 private static async Task<Servers.Servers> LoadServers()
422 { 425 {
423 if (!Directory.Exists(Constants.UserApplicationDirectory)) 426 if (!Directory.Exists(Constants.UserApplicationDirectory))
424 Directory.CreateDirectory(Constants.UserApplicationDirectory); 427 Directory.CreateDirectory(Constants.UserApplicationDirectory);
425   428  
426 var deserializationResult = 429 var deserializationResult =
427 await Serialization.Deserialize<Servers.Servers>(Constants.ServersFile, 430 await Serialization.Deserialize<Servers.Servers>(Constants.ServersFile,
428 "urn:winify-servers-schema", "Servers.xsd", CancellationToken.None); 431 "urn:winify-servers-schema", "Servers.xsd", CancellationToken.None);
429   432  
430 switch (deserializationResult) 433 switch (deserializationResult)
431 { 434 {
432 case SerializationSuccess<Servers.Servers> serializationSuccess: 435 case SerializationSuccess<Servers.Servers> serializationSuccess:
433 // Decrypt password. 436 // Decrypt password.
434 var deviceId = Miscellaneous.GetMachineGuid(); 437 var deviceId = Miscellaneous.GetMachineGuid();
435 var @protected = new Servers.Servers 438 var @protected = new Servers.Servers
436 { 439 {
437 Server = new BindingListWithCollectionChanged<Server>() 440 Server = new BindingListWithCollectionChanged<Server>()
438 }; 441 };
439 foreach (var server in serializationSuccess.Result.Server) 442 foreach (var server in serializationSuccess.Result.Server)
440 { 443 {
441 var unarmored = Convert.FromBase64String(server.Password); 444 var unarmored = Convert.FromBase64String(server.Password);
442 byte[] decrypted; 445 byte[] decrypted;
443 try 446 try
444 { 447 {
445 decrypted = await AES.Decrypt(unarmored, deviceId); 448 decrypted = await AES.Decrypt(unarmored, deviceId);
446 } 449 }
447 catch(Exception exception) 450 catch(Exception exception)
448 { 451 {
449 Log.Warning(exception, $"Could not decrypt password for server {server.Name} in configuration file."); 452 Log.Warning(exception, $"Could not decrypt password for server {server.Name} in configuration file.");
450 continue; 453 continue;
451 } 454 }
452   455  
453 var password = Encoding.UTF8.GetString(decrypted); 456 var password = Encoding.UTF8.GetString(decrypted);
454   457  
455 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, password)); 458 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, password));
456 } 459 }
457   460  
458 return @protected; 461 return @protected;
459   462  
460 case SerializationFailure serializationFailure: 463 case SerializationFailure serializationFailure:
461 Log.Warning(serializationFailure.Exception, "Unable to load servers."); 464 Log.Warning(serializationFailure.Exception, "Unable to load servers.");
462 return new Servers.Servers(); 465 return new Servers.Servers();
463   466  
464 default: 467 default:
465 return new Servers.Servers(); 468 return new Servers.Servers();
466 } 469 }
467 } 470 }
468   471  
469 #endregion 472 #endregion
470 } 473 }
471 } 474 }
472   475  
473
Generated by GNU Enscript 1.6.5.90.
476
Generated by GNU Enscript 1.6.5.90.
474   477  
475   478  
476   479