Hush – Diff between revs 2 and 3

Subversion Repositories:
Rev:
Show entire fileIgnore whitespace
Rev 2 Rev 3
Line 6... Line 6...
6 using System.Linq; 6 using System.Linq;
7 using System.Net; 7 using System.Net;
8 using System.Threading; 8 using System.Threading;
9 using System.Threading.Tasks; 9 using System.Threading.Tasks;
10 using System.Windows.Forms; 10 using System.Windows.Forms;
11 using Gma.System.MouseKeyHook; -  
12 using Hush.Chat; 11 using Hush.Chat;
13 using Hush.Communication; 12 using Hush.Communication;
14 using Hush.Discovery; 13 using Hush.Discovery;
15 using Hush.Properties; 14 using Hush.Properties;
16 using Hush.Utilities; 15 using Hush.Utilities;
-   16 using MQTTnet.Extensions.ManagedClient;
-   17 using MQTTnet.Server;
17 using WingMan.Communication; 18 using WingMan.Communication;
18 using Message = System.Windows.Forms.Message; -  
Line 19... Line 19...
19   19  
20 namespace Hush 20 namespace Hush
21 { 21 {
22 public partial class Hush : Form 22 public partial class Hush : Form
-   23 {
-   24 private static TaskScheduler FormTaskScheduler { get; set; }
-   25 private static CancellationTokenSource FormCancellationTokenSource { get; set; }
-   26 private static MqttCommunication MqttCommunication { get; set; }
-   27 private static ChatMessageSynchronizer ChatMessageSynchronizer { get; set; }
-   28 private static Discovery.Discovery Discovery { get; set; }
23 { 29  
24 public Hush() 30 public Hush()
25 { 31 {
Line 26... Line 32...
26 InitializeComponent(); 32 InitializeComponent();
27   33  
Line 28... Line -...
28 FormTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); -  
29 FormCancellationTokenSource = new CancellationTokenSource(); -  
30   -  
31 // Initialize a message buffer. 34 FormTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
32 Messages = new List<string>(); 35 FormCancellationTokenSource = new CancellationTokenSource();
33   36  
34 // Bind to settings changed event. 37 // Bind to settings changed event.
Line 35... Line -...
35 Settings.Default.SettingsLoaded += DefaultOnSettingsLoaded; -  
36 Settings.Default.SettingsSaving += DefaultOnSettingsSaving; -  
37 Settings.Default.PropertyChanged += DefaultOnPropertyChanged; -  
38   -  
39 // Set up keyboard hook. 38 Settings.Default.SettingsLoaded += DefaultOnSettingsLoaded;
40 MouseKeyGlobalHook = Hook.GlobalEvents(); 39 Settings.Default.SettingsSaving += DefaultOnSettingsSaving;
41 MouseKeyGlobalHook.KeyDown += MouseKeyGlobalHookOnKeyDown; 40 Settings.Default.PropertyChanged += DefaultOnPropertyChanged;
42   41  
Line 43... Line 42...
43 // Set up discovery. 42 // Set up discovery.
44 Discovery = new Discovery.Discovery(Constants.AssemblyName, FormCancellationTokenSource.Token, 43 Discovery = new Discovery.Discovery(Constants.AssemblyName, FormCancellationTokenSource.Token,
-   44 FormTaskScheduler);
-   45 Discovery.OnPortMapFailed += OnDiscoveryPortMapFailed;
45 FormTaskScheduler); 46  
46 Discovery.OnPortMapFailed += OnDiscoveryPortMapFailed; 47 // Bind to MQTT events.
-   48 MqttCommunication = new MqttCommunication(FormTaskScheduler, FormCancellationTokenSource.Token);
-   49 MqttCommunication.OnClientConnectionFailed += MqttOnClientConnectionFailed;
Line 47... Line 50...
47   50 MqttCommunication.OnClientAuthenticationFailed += MqttOnClientAuthenticationFailed;
48 // Bind to MQTT events. 51 MqttCommunication.OnClientConnected += MqttOnClientConnected;
-   52 MqttCommunication.OnClientDisconnected += MqttOnClientDisconnected;
49 MqttCommunication = new MqttCommunication(FormTaskScheduler, FormCancellationTokenSource.Token); 53 MqttCommunication.OnServerClientConnected += MqttCommunicationOnOnServerClientConnected;
50 // TODO implement events. 54 MqttCommunication.OnServerClientDisconnected += MqttOnServerClientDisconnected;
51 //MqttCommunication. 55  
Line 52... Line -...
52   -  
53 // Start message synchronizer. -  
54 ChatMessageSynchronizer = new ChatMessageSynchronizer(Constants.MqttTopic, MqttCommunication, FormTaskScheduler, -  
55 FormCancellationTokenSource.Token); -  
56 ChatMessageSynchronizer.OnMessageReceived += OnMessageReceived; -  
57 } -  
58   -  
59 private static IKeyboardMouseEvents MouseKeyGlobalHook { get; set; } -  
60 private static TaskScheduler FormTaskScheduler { get; set; } -  
61 private static CancellationTokenSource FormCancellationTokenSource { get; set; } -  
62 private static MqttCommunication MqttCommunication { get; set; } -  
63 private static ChatMessageSynchronizer ChatMessageSynchronizer { get; set; } -  
64 private static Discovery.Discovery Discovery { get; set; } -  
65 private static List<string> Messages { get; set; } -  
66   -  
67 private void MouseKeyGlobalHookOnKeyDown(object sender, KeyEventArgs keyEventArgs) -  
68 { -  
69 // Bind to CTRL+C -  
70 if (!keyEventArgs.Control || keyEventArgs.KeyCode != Keys.C) -  
71 return; -  
72   -  
73 ActiveControl = messageTextBox; -  
74 messageTextBox.Focus(); -  
75 } -  
76   -  
77 private void OnDiscoveryPortMapFailed(object sender, DiscoveryFailedEventArgs args) -  
78 { -  
79 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; -  
80 notifyIcon1.BalloonTipTitle = Strings.Network_warning; -  
81 notifyIcon1.BalloonTipText = Strings.Failed_to_create_automatic_NAT_port_mapping; -  
82 notifyIcon1.ShowBalloonTip(1000); -  
83 } -  
84   -  
85 private void OnMessageReceived(object sender, ChatMessageReceivedEventArgs e) -  
86 { -  
87 var message = $"{e.Nick} : {e.Message}"; -  
88   -  
89 Messages.Add(message); -  
90   -  
91 // Keep the content of the text box limited to the size of the displayed text. -  
92 var lineHeight = TextRenderer.MeasureText(message, chatTextBox.Font).Height; -  
93 var linesPerPage = (int) Math.Ceiling(1.0f * chatTextBox.ClientSize.Height / lineHeight); -  
94   -  
95 if (Messages.Count > linesPerPage) -  
96 Messages.RemoveRange(0, Messages.Count - 1 - linesPerPage); -  
97   -  
98 chatTextBox.Text = string.Join(Environment.NewLine, Messages); -  
99 } -  
100   -  
101 private async void DefaultOnPropertyChanged(object sender, PropertyChangedEventArgs e) -  
102 { -  
103 if (string.Equals(e.PropertyName, "LaunchOnBoot")) -  
104 LaunchOnBoot.Set(Settings.Default.LaunchOnBoot); -  
105   -  
106 if (string.Equals(e.PropertyName, "Start")) -  
107 await ToggleStart(); -  
108 } -  
109   -  
110 private async Task ToggleStart() -  
111 { -  
112 switch (Settings.Default.Mode) -  
113 { -  
114 case "Server": -  
115 await StopServer(); -  
116   -  
117 if (!Settings.Default.Start) -  
118 break; -  
119   -  
120 try -  
121 { -  
122 await StartServer(); -  
123 } -  
124 catch (ToolTippedException ex) -  
125 { -  
126 notifyIcon1.BalloonTipIcon = ex.Icon; -  
127 notifyIcon1.BalloonTipTitle = ex.Title; -  
128 notifyIcon1.BalloonTipText = ex.Body; -  
129 notifyIcon1.ShowBalloonTip(1000); -  
130 } -  
131   -  
132 break; -  
133 case "Client": -  
134 await StopClient(); -  
135   -  
136 if (!Settings.Default.Start) -  
137 break; -  
138   -  
139 try -  
140 { -  
141 await StartClient(); -  
142 } -  
143 catch (ToolTippedException ex) -  
144 { -  
145 notifyIcon1.BalloonTipIcon = ex.Icon; -  
146 notifyIcon1.BalloonTipTitle = ex.Title; -  
147 notifyIcon1.BalloonTipText = ex.Body; -  
148 notifyIcon1.ShowBalloonTip(1000); -  
149 } -  
150   -  
151 break; -  
152 } -  
153   -  
154 startToolStripMenuItem.Checked = Settings.Default.Start; -  
155 } -  
156   -  
157 private async Task StopClient() -  
158 { -  
159 // Stop the client if it is already started. -  
160 await MqttCommunication.Stop(); -  
161 } -  
162   -  
163 private async Task StopServer() -  
164 { -  
165 // Remove UPnP and Pmp mappings. -  
166 await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ => -  
167 { -  
168 await Discovery.DeleteMapping(DiscoveryType.Upnp, MqttCommunication.Port); -  
169 await Discovery.DeleteMapping(DiscoveryType.Pmp, MqttCommunication.Port); -  
170 }, -  
171 FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler); -  
172   -  
173 // Stop the MQTT server if it is running. -  
174 await MqttCommunication.Stop(); -  
175 } -  
176   -  
177 private async Task StartClient() -  
178 { -  
179 if (!IPAddress.TryParse(Settings.Default.Address, out var address)) -  
180 try -  
181 { -  
182 var getHostAddresses = await Dns.GetHostAddressesAsync(Settings.Default.Address); -  
183 if (!getHostAddresses.Any()) -  
184 throw new Exception(); -  
185   -  
186 address = getHostAddresses.FirstOrDefault(); -  
187 } -  
188 catch -  
189 { -  
190 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, -  
191 $"{Strings.Unable_to_determine_address} {Settings.Default.Address}"); -  
192 } -  
193   -  
194 if (!uint.TryParse(Settings.Default.Port, out var port)) -  
195 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, -  
196 $"{Strings.Unable_to_determine_port} {Settings.Default.Port}"); -  
197   -  
198   -  
199 if (string.IsNullOrEmpty(Settings.Default.Nick)) -  
200 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set); -  
201   -  
202 if (string.IsNullOrEmpty(Settings.Default.Password)) -  
203 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set); -  
204   -  
205 if (!await MqttCommunication -  
206 .Start(MqttCommunicationType.Client, address, (int) port, Settings.Default.Nick, -  
207 Settings.Default.Password, -  
208 new[] {Constants.MqttTopic})) -  
209 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_client); -  
210 } -  
211   -  
212 private async Task StartServer() -  
213 { -  
214 if (!IPAddress.TryParse(Settings.Default.Address, out var address)) -  
215 try -  
216 { -  
217 address = Dns.GetHostAddresses(Settings.Default.Address).FirstOrDefault(); -  
218 } -  
219 catch -  
220 { -  
221 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, -  
222 $"{Strings.Unable_to_determine_address} {Settings.Default.Address}"); -  
223 } -  
224   -  
225 if (!uint.TryParse(Settings.Default.Port, out var port)) -  
226 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, -  
227 $"{Strings.Unable_to_determine_port} {Settings.Default.Port}"); -  
228   -  
229   -  
230 if (string.IsNullOrEmpty(Settings.Default.Nick)) -  
231 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set); -  
232   -  
233 if (string.IsNullOrEmpty(Settings.Default.Password)) -  
234 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set); -  
235   -  
236 // Try to reserve port: try UPnP followed by PMP. -  
237 await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ => -  
238 { -  
239 if (!await Discovery.CreateMapping(DiscoveryType.Upnp, (int) port)) -  
240 await Discovery.CreateMapping(DiscoveryType.Pmp, (int) port); -  
241 }, -  
242 FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler); -  
243   -  
244 // Start the MQTT server. -  
245 if (!await MqttCommunication -  
246 .Start(MqttCommunicationType.Server, address, (int) port, Settings.Default.Nick, -  
247 Settings.Default.Password, new[] {Constants.MqttTopic})) -  
248 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_server); -  
249 } -  
250   -  
251 private void DefaultOnSettingsSaving(object sender, CancelEventArgs e) -  
Line 252... Line 56...
252 { 56 // Start message synchronizer.
253 } 57 ChatMessageSynchronizer = new ChatMessageSynchronizer(Constants.MqttTopic, MqttCommunication,
254   58 FormTaskScheduler,
255 private void DefaultOnSettingsLoaded(object sender, SettingsLoadedEventArgs e) 59 FormCancellationTokenSource.Token);
256 { 60 ChatMessageSynchronizer.OnMessageReceived += OnMessageReceived;
257 LaunchOnBoot.Set(Settings.Default.LaunchOnBoot); 61 }
258 } -  
259   -  
260 /// <summary> -  
261 /// Clean up any resources being used. 62  
262 /// </summary> 63  
Line 263... Line 64...
263 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 64 /// <summary>
264 protected override void Dispose(bool disposing) 65 /// Clean up any resources being used.
Line 276... Line 77...
276   77  
277 if (disposing && components != null) components.Dispose(); 78 if (disposing && components != null) components.Dispose();
278 base.Dispose(disposing); 79 base.Dispose(disposing);
Line 279... Line -...
279 } -  
280   -  
281 private void OnMouseDown(object sender, MouseEventArgs e) -  
282 { 80 }
283 if (e.Button == MouseButtons.Left) -  
284 { -  
285 DllImports.ReleaseCapture(); -  
286 DllImports.SendMessage(Handle, DllImports.WM_NCLBUTTONDOWN, DllImports.HT_CAPTION, 0); -  
Line 287... Line 81...
287 } 81  
288 } 82 #region Overrides
289   83  
290 protected override void OnPaintBackground(PaintEventArgs e) 84 protected override void OnPaintBackground(PaintEventArgs e)
Line 368... Line 162...
368   162  
369 if (!handled) 163 if (!handled)
370 base.WndProc(ref m); 164 base.WndProc(ref m);
Line -... Line 165...
-   165 }
-   166  
-   167 #endregion
-   168  
-   169 #region Event Handlers
-   170  
-   171 private void MqttOnServerClientDisconnected(object sender,
-   172 MqttClientDisconnectedEventArgs mqttClientDisconnectedEventArgs)
-   173 {
-   174 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
-   175 notifyIcon1.BalloonTipTitle = Strings.Network_warning;
-   176 notifyIcon1.BalloonTipText = $"{Strings.Client_disconnected}";
-   177 notifyIcon1.ShowBalloonTip(1000);
-   178 }
-   179  
-   180  
-   181 private void MqttCommunicationOnOnServerClientConnected(object sender,
-   182 MqttClientConnectedEventArgs mqttClientConnectedEventArgs)
-   183 {
-   184 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
-   185 notifyIcon1.BalloonTipTitle = Strings.Network_warning;
-   186 notifyIcon1.BalloonTipText = $"{Strings.Client_connected}";
-   187 notifyIcon1.ShowBalloonTip(1000);
-   188 }
-   189  
-   190 private void MqttOnClientDisconnected(object sender,
-   191 MQTTnet.Client.MqttClientDisconnectedEventArgs mqttClientDisconnectedEventArgs)
-   192 {
-   193 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
-   194 notifyIcon1.BalloonTipTitle = Strings.Network_warning;
-   195 notifyIcon1.BalloonTipText = $"{Strings.Client_disconnected}";
-   196 notifyIcon1.ShowBalloonTip(1000);
-   197 }
-   198  
-   199 private void MqttOnClientConnected(object sender,
-   200 MQTTnet.Client.MqttClientConnectedEventArgs mqttClientConnectedEventArgs)
-   201 {
-   202 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
-   203 notifyIcon1.BalloonTipTitle = Strings.Network_warning;
-   204 notifyIcon1.BalloonTipText = $"{Strings.Client_connected}";
-   205 notifyIcon1.ShowBalloonTip(1000);
-   206 }
-   207  
-   208 private void MqttOnClientAuthenticationFailed(object sender,
-   209 MqttAuthenticationFailureEventArgs mqttAuthenticationFailureEventArgs)
-   210 {
-   211 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
-   212 notifyIcon1.BalloonTipTitle = Strings.Network_warning;
-   213 notifyIcon1.BalloonTipText = $"{Strings.Failed_to_authenticate_to_server}";
-   214 notifyIcon1.ShowBalloonTip(1000);
-   215 }
-   216  
-   217 private void MqttOnClientConnectionFailed(object sender,
-   218 MqttManagedProcessFailedEventArgs mqttManagedProcessFailedEventArgs)
-   219 {
-   220 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
-   221 notifyIcon1.BalloonTipTitle = Strings.Network_warning;
-   222 notifyIcon1.BalloonTipText =
-   223 $"{Strings.Failed_to_connect_to_server} {mqttManagedProcessFailedEventArgs.Exception.Message}";
-   224 notifyIcon1.ShowBalloonTip(1000);
-   225 }
-   226  
-   227 private void OnDiscoveryPortMapFailed(object sender, DiscoveryFailedEventArgs args)
-   228 {
-   229 notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
-   230 notifyIcon1.BalloonTipTitle = Strings.Network_warning;
-   231 notifyIcon1.BalloonTipText = Strings.Failed_to_create_automatic_NAT_port_mapping;
-   232 notifyIcon1.ShowBalloonTip(1000);
-   233 }
-   234  
-   235 private void OnMessageReceived(object sender, ChatMessageReceivedEventArgs e)
-   236 {
-   237 var message = $"{e.Nick} : {e.Message}{Environment.NewLine}";
-   238 chatTextBox.AppendText(message);
-   239 }
-   240  
-   241 private async void DefaultOnPropertyChanged(object sender, PropertyChangedEventArgs e)
-   242 {
-   243 LaunchOnBoot.Set(Settings.Default.LaunchOnBoot);
-   244 await ToggleStart();
-   245 }
-   246  
-   247 private void DefaultOnSettingsSaving(object sender, CancelEventArgs e)
-   248 {
-   249 }
-   250  
-   251 private void DefaultOnSettingsLoaded(object sender, SettingsLoadedEventArgs e)
-   252 {
-   253 LaunchOnBoot.Set(Settings.Default.LaunchOnBoot);
-   254 }
-   255  
-   256 private void OnMouseDown(object sender, MouseEventArgs e)
-   257 {
-   258 if (e.Button == MouseButtons.Left)
-   259 {
-   260 DllImports.ReleaseCapture();
-   261 DllImports.SendMessage(Handle, DllImports.WM_NCLBUTTONDOWN, DllImports.HT_CAPTION, 0);
-   262 }
371 } 263 }
372   264  
373 private void HushFocus(object sender, EventArgs e) 265 private void HushFocus(object sender, EventArgs e)
374 { 266 {
Line 454... Line 346...
454 var toolStripMenuItem = (ToolStripTextBox) sender; 346 var toolStripMenuItem = (ToolStripTextBox) sender;
Line 455... Line 347...
455   347  
456 Settings.Default.Port = toolStripMenuItem.Text; 348 Settings.Default.Port = toolStripMenuItem.Text;
Line -... Line 349...
-   349 }
-   350  
457 } 351 #endregion
458   352  
-   353 private async Task ToggleStart()
-   354 {
-   355 switch (Settings.Default.Mode)
459 private void ChatTextBox_TextChanged(object sender, EventArgs e) 356 {
-   357 case "Server":
-   358 await StopServer();
-   359  
Line -... Line 360...
-   360 if (!Settings.Default.Start)
-   361 break;
-   362  
-   363 try
-   364 {
-   365 await StartServer();
-   366 }
-   367 catch (ToolTippedException ex)
-   368 {
-   369 notifyIcon1.BalloonTipIcon = ex.Icon;
-   370 notifyIcon1.BalloonTipTitle = ex.Title;
-   371 notifyIcon1.BalloonTipText = ex.Body;
-   372 notifyIcon1.ShowBalloonTip(1000);
-   373 }
460 { 374  
-   375 break;
-   376 case "Client":
-   377 await StopClient();
-   378  
-   379 if (!Settings.Default.Start)
-   380 break;
-   381  
-   382 try
-   383 {
-   384 await StartClient();
-   385 }
-   386 catch (ToolTippedException ex)
-   387 {
-   388 notifyIcon1.BalloonTipIcon = ex.Icon;
-   389 notifyIcon1.BalloonTipTitle = ex.Title;
-   390 notifyIcon1.BalloonTipText = ex.Body;
-   391 notifyIcon1.ShowBalloonTip(1000);
-   392 }
-   393  
-   394 break;
-   395 }
-   396  
-   397 startToolStripMenuItem.Checked = Settings.Default.Start;
-   398 }
-   399  
-   400 private async Task StopClient()
-   401 {
-   402 // Stop the client if it is already started.
-   403 await MqttCommunication.Stop();
-   404 }
-   405  
-   406 private async Task StopServer()
-   407 {
-   408 // Remove UPnP and Pmp mappings.
-   409 await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ =>
-   410 {
-   411 await Discovery.DeleteMapping(DiscoveryType.Upnp, MqttCommunication.Port);
-   412 await Discovery.DeleteMapping(DiscoveryType.Pmp, MqttCommunication.Port);
-   413 },
-   414 FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler);
-   415  
-   416 // Stop the MQTT server if it is running.
-   417 await MqttCommunication.Stop();
-   418 }
-   419  
-   420 private async Task StartClient()
-   421 {
-   422 if (!IPAddress.TryParse(Settings.Default.Address, out var address))
-   423 try
-   424 {
-   425 var getHostAddresses = await Dns.GetHostAddressesAsync(Settings.Default.Address);
-   426 if (!getHostAddresses.Any())
-   427 throw new Exception();
-   428  
-   429 address = getHostAddresses.FirstOrDefault();
-   430 }
-   431 catch
-   432 {
-   433 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error,
-   434 $"{Strings.Unable_to_determine_address} {Settings.Default.Address}");
-   435 }
-   436  
-   437 if (!uint.TryParse(Settings.Default.Port, out var port))
-   438 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error,
-   439 $"{Strings.Unable_to_determine_port} {Settings.Default.Port}");
-   440  
-   441  
-   442 if (string.IsNullOrEmpty(Settings.Default.Nick))
-   443 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set);
-   444  
-   445 if (string.IsNullOrEmpty(Settings.Default.Password))
-   446 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set);
-   447  
-   448 if (!await MqttCommunication
-   449 .Start(MqttCommunicationType.Client, address, (int) port, Settings.Default.Nick,
-   450 Settings.Default.Password,
-   451 new[] {Constants.MqttTopic}))
-   452 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_client);
-   453 }
-   454  
-   455 private async Task StartServer()
-   456 {
-   457 if (!IPAddress.TryParse(Settings.Default.Address, out var address))
-   458 try
-   459 {
-   460 address = Dns.GetHostAddresses(Settings.Default.Address).FirstOrDefault();
-   461 }
-   462 catch
-   463 {
-   464 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error,
-   465 $"{Strings.Unable_to_determine_address} {Settings.Default.Address}");
-   466 }
-   467  
-   468 if (!uint.TryParse(Settings.Default.Port, out var port))
-   469 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error,
-   470 $"{Strings.Unable_to_determine_port} {Settings.Default.Port}");
-   471  
-   472  
-   473 if (string.IsNullOrEmpty(Settings.Default.Nick))
-   474 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set);
-   475  
-   476 if (string.IsNullOrEmpty(Settings.Default.Password))
-   477 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set);
-   478  
-   479 // Try to reserve port: try UPnP followed by PMP.
-   480 await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ =>
-   481 {
-   482 if (!await Discovery.CreateMapping(DiscoveryType.Upnp, (int) port))
-   483 await Discovery.CreateMapping(DiscoveryType.Pmp, (int) port);
-   484 },
-   485 FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler);
-   486  
-   487 // Start the MQTT server.
-   488 if (!await MqttCommunication
461 var textBox = (TextBox) sender; 489 .Start(MqttCommunicationType.Server, address, (int) port, Settings.Default.Nick,
462   490 Settings.Default.Password, new[] {Constants.MqttTopic}))
463 textBox.ScrollToCaret(); 491 throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_server);
464 } 492 }