Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
CanControlQuestion.cs
1using System;
2using System.Collections.Generic;
3using System.Threading.Tasks;
4using System.Windows;
5using System.Windows.Controls;
6using Waher.Events;
13
15{
17 {
18 private SortedDictionary<string, bool> parametersSorted = null;
19 private ListBox parametersListBox = null;
20 private ProvisioningClient client;
21 private QuestionView questionView;
22 private OperationRange range;
23 private string parameter = null;
24 private string[] parameterNames = null;
25 private string[] availableParameterNames = null;
26 private bool registered = false;
27
28 public CanControlQuestion()
29 : base()
30 {
31 }
32
33 [DefaultValueNull]
34 public string[] ParameterNames
35 {
36 get => this.parameterNames;
37 set => this.parameterNames = value;
38 }
39
40 [DefaultValueNull]
41 public string[] AvailableParameterNames
42 {
43 get => this.availableParameterNames;
44 set => this.availableParameterNames = value;
45 }
46
47 public override string QuestionString => "Allowed to control?";
48
49 public override void PopulateDetailsDialog(QuestionView QuestionView, ProvisioningClient ProvisioningClient)
50 {
51 StackPanel Details = QuestionView.Details;
52 TextBlock TextBlock;
53 ListBox ListBox;
54 Button Button;
55
56 this.client = ProvisioningClient;
57 this.questionView = QuestionView;
58
59 Details.Children.Add(new TextBlock()
60 {
61 FontSize = 18,
62 FontWeight = FontWeights.Bold,
63 Text = "Allowed to control?"
64 });
65
66 Details.Children.Add(TextBlock = new TextBlock()
67 {
68 TextWrapping = TextWrapping.Wrap,
69 Margin = new Thickness(0, 6, 0, 6)
70 });
71
72 TextBlock.Inlines.Add("Device: ");
73 this.AddJidName(this.JID, ProvisioningClient, TextBlock);
74
75 this.AddNodeInfo(Details);
76
77 Details.Children.Add(TextBlock = new TextBlock()
78 {
79 TextWrapping = TextWrapping.Wrap,
80 Margin = new Thickness(0, 6, 0, 6)
81 });
82
83 TextBlock.Inlines.Add("Caller: ");
84 this.AddJidName(this.RemoteJID, ProvisioningClient, TextBlock);
85
86
87 Details.Children.Add(new Label()
88 {
89 Content = "Parameter restriction:",
90 Margin = new Thickness(0, 6, 0, 0)
91 });
92
93 Details.Children.Add(ListBox = new ListBox()
94 {
95 MaxHeight = 150,
96 SelectionMode = SelectionMode.Multiple,
97 Margin = new Thickness(0, 0, 0, 6)
98 });
99
100 this.parametersListBox = ListBox;
101
102 if (this.availableParameterNames is null)
103 {
104 if (!(this.parameterNames is null))
105 {
106 foreach (string ParameterName in this.parameterNames)
107 {
108 ListBox.Items.Add(new ListBoxItem()
109 {
110 Content = ParameterName,
111 IsSelected = true,
112 Tag = ParameterName
113 });
114 }
115 }
116 }
117 else
118 {
119 foreach (string ParameterName in this.availableParameterNames)
120 {
121 ListBox.Items.Add(new ListBoxItem()
122 {
123 Content = ParameterName,
124 IsSelected = (this.parameterNames is null || Array.IndexOf<string>(this.parameterNames, ParameterName) >= 0),
125 Tag = ParameterName
126 });
127 }
128 }
129
130 StackPanel StackPanel = CanReadQuestion.AddAllClearButtons(Details, ListBox);
131
132 if (this.availableParameterNames is null)
133 {
134 StackPanel.Children.Add(Button = new Button()
135 {
136 Margin = new Thickness(6, 6, 6, 6),
137 Padding = new Thickness(20, 0, 20, 0),
138 Content = "Get List",
139 Tag = ListBox
140 });
141
142 Button.Click += this.GetListButton_Click;
143 }
144
145 Details.Children.Add(TextBlock = new TextBlock()
146 {
147 TextWrapping = TextWrapping.Wrap,
148 Margin = new Thickness(0, 6, 0, 6),
149 Text = "Is the caller allowed to control your device?"
150 });
151
152 Details.Children.Add(Button = new Button()
153 {
154 Margin = new Thickness(0, 6, 0, 6),
155 Content = "Yes"
156 });
157
158 Button.Click += this.YesButton_Click;
159
160 Details.Children.Add(Button = new Button()
161 {
162 Margin = new Thickness(0, 6, 0, 6),
163 Content = "No"
164 });
165
166 Button.Click += this.NoButton_Click;
167
168 string s = this.RemoteJID;
169 int i = s.IndexOf('@');
170 if (i >= 0)
171 {
172 s = s.Substring(i + 1);
173
174 Details.Children.Add(Button = new Button()
175 {
176 Margin = new Thickness(0, 6, 0, 6),
177 Content = "Yes, to anyone from " + s
178 });
179
180 Button.Click += this.YesDomainButton_Click;
181
182 Details.Children.Add(Button = new Button()
183 {
184 Margin = new Thickness(0, 6, 0, 6),
185 Content = "No, to no one from " + s
186 });
187
188 Button.Click += this.NoDomainButton_Click;
189 }
190
191 Details.Children.Add(Button = new Button()
192 {
193 Margin = new Thickness(0, 6, 0, 6),
194 Content = "Yes, to anyone"
195 });
196
197 Button.Click += this.YesAllButton_Click;
198
199 Details.Children.Add(Button = new Button()
200 {
201 Margin = new Thickness(0, 6, 0, 6),
202 Content = "No, to no one"
203 });
204
205 Button.Click += this.NoAllButton_Click;
206
207 this.AddTokens(Details, this.client, this.YesTokenButton_Click, this.NoTokenButton_Click);
208 }
209
210 private void GetListButton_Click(object Sender, RoutedEventArgs e)
211 {
212 XmppClient Client = this.client.Client;
213
214 ((Button)Sender).IsEnabled = false;
215
216 RosterItem Item = Client[this.JID];
217 if (Item is null || Item.State == SubscriptionState.None || Item.State == SubscriptionState.From)
218 {
219 if (!this.registered)
220 {
221 this.registered = true;
222 this.questionView.Owner.RegisterRosterEventHandler(this.JID, this.RosterItemUpdated);
223 }
224
225 Client.RequestPresenceSubscription(this.JID);
226 }
227 else if (!Item.HasLastPresence || !Item.LastPresence.IsOnline)
228 Client.RequestPresenceSubscription(this.JID);
229 else
230 this.DoRequest(Item);
231 }
232
233 public override void Dispose()
234 {
235 if (this.registered)
236 {
237 this.registered = false;
238 this.questionView.Owner.UnregisterRosterEventHandler(this.JID, this.RosterItemUpdated);
239 }
240
241 base.Dispose();
242 }
243
244 private Task RosterItemUpdated(object Sender, RosterItem Item)
245 {
246 if ((Item.State == SubscriptionState.Both || Item.State == SubscriptionState.To) && Item.HasLastPresence && Item.LastPresence.IsOnline)
247 {
248 this.questionView.Owner.UnregisterRosterEventHandler(this.JID, this.RosterItemUpdated);
249 this.DoRequest(Item);
250 }
251
252 return Task.CompletedTask;
253 }
254
255 private void DoRequest(RosterItem Item)
256 {
257 this.parametersSorted = new SortedDictionary<string, bool>();
258
259 if (this.IsNode)
260 {
261 this.questionView.Owner.ControlClient.GetForm(Item.LastPresenceFullJid, "en", this.ControlFormResponse, null,
262 this.GetNodeReference());
263 }
264 else
265 this.questionView.Owner.ControlClient.GetForm(Item.LastPresenceFullJid, "en", this.ControlFormResponse, null);
266 }
267
268 private async Task ControlFormResponse(object Sender, DataFormEventArgs e)
269 {
270 try
271 {
272 if (e.Ok)
273 {
274 string[] Parameters;
275
276 lock (this.parametersSorted)
277 {
278 foreach (Field F in e.Form.Fields)
279 {
280 if (!F.ReadOnly && !F.Exclude)
281 this.parametersSorted[F.Var] = true;
282 }
283
284 Parameters = new string[this.parametersSorted.Count];
285 this.parametersSorted.Keys.CopyTo(Parameters, 0);
286 }
287
288 this.availableParameterNames = Parameters;
289 await Database.Update(this);
290
291 MainWindow.UpdateGui(() =>
292 {
293 SortedDictionary<string, bool> Selected = null;
294 bool AllSelected = this.parameterNames is null;
295
296 if (!AllSelected)
297 {
298 Selected = new SortedDictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
299
300 foreach (ListBoxItem Item in this.parametersListBox.Items)
301 {
302 if (Item.IsSelected)
303 Selected[(string)Item.Tag] = true;
304 }
305 }
306
307 this.parametersListBox.Items.Clear();
308
309 foreach (string ParameterName in this.availableParameterNames)
310 {
311 this.parametersListBox.Items.Add(new ListBoxItem()
312 {
313 Content = ParameterName,
314 IsSelected = AllSelected || Selected.ContainsKey(ParameterName),
315 Tag = ParameterName
316 });
317 }
318
319 return Task.CompletedTask;
320 });
321 }
322 else
323 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to get control form." : e.ErrorText);
324 }
325 catch (Exception ex)
326 {
327 ex = Log.UnnestException(ex);
328 MainWindow.ErrorBox(ex.Message);
329 }
330 }
331
332 private string[] GetParameters()
333 {
334 List<string> Result = new List<string>();
335 bool All = true;
336
337 foreach (ListBoxItem Item in this.parametersListBox.Items)
338 {
339 if (Item.IsSelected)
340 Result.Add((string)Item.Tag);
341 else
342 All = false;
343 }
344
345 if (this.availableParameterNames is null || !All)
346 return Result.ToArray();
347 else
348 return null;
349 }
350
351 private async Task RuleCallback(object Sender, IqResultEventArgs e)
352 {
353 try
354 {
355 if (e.Ok)
356 await this.Processed(this.questionView);
357 else
358 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to set rule." : e.ErrorText);
359 }
360 catch (Exception ex)
361 {
362 ex = Log.UnnestException(ex);
363 MainWindow.ErrorBox(ex.Message);
364 }
365 }
366
367 private void NoAllButton_Click(object Sender, RoutedEventArgs e)
368 {
369 this.range = OperationRange.All;
370 this.client.CanControlResponseAll(this.Sender, this.JID, this.RemoteJID, this.Key, false, this.GetParameters(), this.GetNodeReference(), this.RuleCallback, null);
371 }
372
373 private void YesAllButton_Click(object Sender, RoutedEventArgs e)
374 {
375 this.range = OperationRange.All;
376 this.client.CanControlResponseAll(this.Sender, this.JID, this.RemoteJID, this.Key, true, this.GetParameters(), this.GetNodeReference(), this.RuleCallback, null);
377 }
378
379 private void NoDomainButton_Click(object Sender, RoutedEventArgs e)
380 {
381 this.range = OperationRange.Domain;
382 this.client.CanControlResponseDomain(this.Sender, this.JID, this.RemoteJID, this.Key, false, this.GetParameters(), this.GetNodeReference(), this.RuleCallback, null);
383 }
384
385 private void YesDomainButton_Click(object Sender, RoutedEventArgs e)
386 {
387 this.range = OperationRange.Domain;
388 this.client.CanControlResponseDomain(this.Sender, this.JID, this.RemoteJID, this.Key, true, this.GetParameters(), this.GetNodeReference(), this.RuleCallback, null);
389 }
390
391 private void NoButton_Click(object Sender, RoutedEventArgs e)
392 {
393 this.range = OperationRange.Caller;
394 this.client.CanControlResponseCaller(this.Sender, this.JID, this.RemoteJID, this.Key, false, this.GetParameters(), this.GetNodeReference(), this.RuleCallback, null);
395 }
396
397 private void YesButton_Click(object Sender, RoutedEventArgs e)
398 {
399 this.range = OperationRange.Caller;
400 this.client.CanControlResponseCaller(this.Sender, this.JID, this.RemoteJID, this.Key, true, this.GetParameters(), this.GetNodeReference(), this.RuleCallback, null);
401 }
402
403 private void NoTokenButton_Click(object Sender, RoutedEventArgs e)
404 {
405 this.TokenButtonClick(Sender, e, false);
406 }
407
408 private void TokenButtonClick(object Sender, RoutedEventArgs _, bool Result)
409 {
410 Button Button = (Button)Sender;
411 object[] P = (object[])Button.Tag;
412 this.parameter = (string)P[0];
413 this.range = (OperationRange)P[1];
414
415 switch (this.range)
416 {
417 case OperationRange.ServiceToken:
418 this.client.CanControlResponseService(this.Sender, this.JID, this.RemoteJID, this.Key, Result, this.GetParameters(), this.parameter, this.GetNodeReference(), this.RuleCallback, null);
419 break;
420
421 case OperationRange.DeviceToken:
422 this.client.CanControlResponseDevice(this.Sender, this.JID, this.RemoteJID, this.Key, Result, this.GetParameters(), this.parameter, this.GetNodeReference(), this.RuleCallback, null);
423 break;
424
425 case OperationRange.UserToken:
426 this.client.CanControlResponseUser(this.Sender, this.JID, this.RemoteJID, this.Key, Result, this.GetParameters(), this.parameter, this.GetNodeReference(), this.RuleCallback, null);
427 break;
428 }
429 }
430
431 private void YesTokenButton_Click(object Sender, RoutedEventArgs e)
432 {
433 this.TokenButtonClick(Sender, e, true);
434 }
435
436 public override bool IsResolvedBy(Question Question)
437 {
439 {
440 if (this.JID != CanControlQuestion.JID)
441 return false;
442
443 switch (this.range)
444 {
445 case OperationRange.Caller:
446 return (this.RemoteJID == CanControlQuestion.RemoteJID);
447
448 case OperationRange.Domain:
449 return (IsFriendQuestion.GetDomain(this.RemoteJID) == IsFriendQuestion.GetDomain(CanControlQuestion.RemoteJID));
450
451 case OperationRange.All:
452 return true;
453
454 case OperationRange.ServiceToken:
455 return CanReadQuestion.MatchesToken(this.parameter, CanControlQuestion.ServiceTokens);
456
457 case OperationRange.DeviceToken:
458 return CanReadQuestion.MatchesToken(this.parameter, CanControlQuestion.DeviceTokens);
459
460 case OperationRange.UserToken:
461 return CanReadQuestion.MatchesToken(this.parameter, CanControlQuestion.UserTokens);
462
463 default:
464 return false;
465 }
466 }
467 else
468 return false;
469 }
470
471 }
472}
Interaction logic for QuestionView.xaml
Interaction logic for xaml
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:818
Event arguments for data form results.
Field[] Fields
Fields in the form.
Definition: DataForm.cs:716
Base class for form fields
Definition: Field.cs:16
Event arguments for responses to IQ queries.
bool Ok
If the response is an OK result response (true), or an error response (false).
Implements an XMPP provisioning client interface.
Task CanControlResponseDevice(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on a device token.
Task CanControlResponseCaller(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on the JID of the caller.
Task CanControlResponseService(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on a service token.
Task CanControlResponseUser(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on a user token.
Task CanControlResponseDomain(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on the domain of the caller.
Task CanControlResponseAll(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, for all future requests.
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
SubscriptionState State
roup Current subscription state.
Definition: RosterItem.cs:268
bool HasLastPresence
If the roster item has received presence from an online resource having the given bare JID.
Definition: RosterItem.cs:425
string LastPresenceFullJid
Full JID of last resource sending online presence.
Definition: RosterItem.cs:343
PresenceEventArgs LastPresence
Last presence received from a resource having this bare JID.
Definition: RosterItem.cs:356
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
Task RequestPresenceSubscription(string BareJid)
Requests subscription of presence information from a contact.
Definition: XmppClient.cs:4919
XmppClient Client
XMPP Client.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:626
SubscriptionState
State of a presence subscription.
Definition: RosterItem.cs:16