Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
CanReadQuestion.cs
1using System;
2using System.Collections.Generic;
3using System.Threading.Tasks;
4using System.Windows;
5using System.Windows.Controls;
6using Waher.Events;
13using Waher.Things;
15
17{
18 public enum OperationRange
19 {
20 Caller,
21 Domain,
22 ServiceToken,
23 DeviceToken,
24 UserToken,
25 All
26 }
27
29 {
30 private SortedDictionary<string, bool> fieldsSorted = null;
31 private ListBox typesListBox = null;
32 private ListBox fieldsListBox = null;
33 private ProvisioningClient client;
34 private QuestionView questionView;
35 private OperationRange range;
36 private string parameter = null;
37 private string[] fieldNames = null;
38 private string[] availableFieldNames = null;
39 private FieldType categories = FieldType.All;
40 private bool registered = false;
41
42 public CanReadQuestion()
43 : base()
44 {
45 }
46
47 [DefaultValueNull]
48 public string[] FieldNames
49 {
50 get => this.fieldNames;
51 set => this.fieldNames = value;
52 }
53
54 [DefaultValueNull]
55 public string[] AvailableFieldNames
56 {
57 get => this.availableFieldNames;
58 set => this.availableFieldNames = value;
59 }
60
61 [DefaultValue(FieldType.All)]
62 public FieldType Categories
63 {
64 get => this.categories;
65 set => this.categories = value;
66 }
67
68 public override string QuestionString => "Allowed to read?";
69
70 public override void PopulateDetailsDialog(QuestionView QuestionView, ProvisioningClient ProvisioningClient)
71 {
72 StackPanel Details = QuestionView.Details;
73 TextBlock TextBlock;
74 ListBox ListBox;
75 Button Button;
76
77 this.client = ProvisioningClient;
78 this.questionView = QuestionView;
79
80 Details.Children.Add(new TextBlock()
81 {
82 FontSize = 18,
83 FontWeight = FontWeights.Bold,
84 Text = "Allowed to read?"
85 });
86
87 Details.Children.Add(TextBlock = new TextBlock()
88 {
89 TextWrapping = TextWrapping.Wrap,
90 Margin = new Thickness(0, 6, 0, 6)
91 });
92
93 TextBlock.Inlines.Add("Device: ");
94 this.AddJidName(this.JID, ProvisioningClient, TextBlock);
95
96 this.AddNodeInfo(Details);
97
98 Details.Children.Add(TextBlock = new TextBlock()
99 {
100 TextWrapping = TextWrapping.Wrap,
101 Margin = new Thickness(0, 6, 0, 6)
102 });
103
104 TextBlock.Inlines.Add("Caller: ");
105 this.AddJidName(this.RemoteJID, ProvisioningClient, TextBlock);
106
107 Details.Children.Add(new Label()
108 {
109 Content = "Categories:",
110 Margin = new Thickness(0, 6, 0, 0)
111 });
112
113 Details.Children.Add(ListBox = new ListBox()
114 {
115 SelectionMode = SelectionMode.Multiple,
116 Margin = new Thickness(0, 0, 0, 6)
117 });
118
119 this.typesListBox = ListBox;
120
121 ListBox.Items.Add(new ListBoxItem()
122 {
123 Content = "Momentary values",
124 IsSelected = (this.categories & FieldType.Momentary) != 0,
125 Tag = FieldType.Momentary
126 });
127
128 ListBox.Items.Add(new ListBoxItem()
129 {
130 Content = "Identity values",
131 IsSelected = (this.categories & FieldType.Identity) != 0,
132 Tag = FieldType.Identity
133 });
134
135 ListBox.Items.Add(new ListBoxItem()
136 {
137 Content = "Status values",
138 IsSelected = (this.categories & FieldType.Status) != 0,
139 Tag = FieldType.Status
140 });
141
142 ListBox.Items.Add(new ListBoxItem()
143 {
144 Content = "Computed values",
145 IsSelected = (this.categories & FieldType.Computed) != 0,
146 Tag = FieldType.Computed
147 });
148
149 ListBox.Items.Add(new ListBoxItem()
150 {
151 Content = "Peak values",
152 IsSelected = (this.categories & FieldType.Peak) != 0,
153 Tag = FieldType.Peak
154 });
155
156 ListBox.Items.Add(new ListBoxItem()
157 {
158 Content = "Historical values",
159 IsSelected = (this.categories & FieldType.Historical) != 0,
160 Tag = FieldType.Historical
161 });
162
163 AddAllClearButtons(Details, ListBox);
164
165
166 Details.Children.Add(new Label()
167 {
168 Content = "Field restriction:",
169 Margin = new Thickness(0, 6, 0, 0)
170 });
171
172 Details.Children.Add(ListBox = new ListBox()
173 {
174 MaxHeight = 150,
175 SelectionMode = SelectionMode.Multiple,
176 Margin = new Thickness(0, 0, 0, 6)
177 });
178
179 this.fieldsListBox = ListBox;
180
181 if (this.availableFieldNames is null)
182 {
183 if (!(this.fieldNames is null))
184 {
185 foreach (string FieldName in this.fieldNames)
186 {
187 ListBox.Items.Add(new ListBoxItem()
188 {
189 Content = FieldName,
190 IsSelected = true,
191 Tag = FieldName
192 });
193 }
194 }
195 }
196 else
197 {
198 foreach (string FieldName in this.availableFieldNames)
199 {
200 ListBox.Items.Add(new ListBoxItem()
201 {
202 Content = FieldName,
203 IsSelected = (this.fieldNames is null || Array.IndexOf<string>(this.fieldNames, FieldName) >= 0),
204 Tag = FieldName
205 });
206 }
207 }
208
209 StackPanel StackPanel = AddAllClearButtons(Details, ListBox);
210
211 if (this.availableFieldNames is null)
212 {
213 StackPanel.Children.Add(Button = new Button()
214 {
215 Margin = new Thickness(6, 6, 6, 6),
216 Padding = new Thickness(20, 0, 20, 0),
217 Content = "Get List",
218 Tag = ListBox
219 });
220
221 Button.Click += this.GetListButton_Click;
222 }
223
224 Details.Children.Add(TextBlock = new TextBlock()
225 {
226 TextWrapping = TextWrapping.Wrap,
227 Margin = new Thickness(0, 6, 0, 6),
228 Text = "Is the caller allowed to read your device?"
229 });
230
231 Details.Children.Add(Button = new Button()
232 {
233 Margin = new Thickness(0, 6, 0, 6),
234 Content = "Yes"
235 });
236
237 Button.Click += this.YesButton_Click;
238
239 Details.Children.Add(Button = new Button()
240 {
241 Margin = new Thickness(0, 6, 0, 6),
242 Content = "No"
243 });
244
245 Button.Click += this.NoButton_Click;
246
247 string s = this.RemoteJID;
248 int i = s.IndexOf('@');
249 if (i >= 0)
250 {
251 s = s.Substring(i + 1);
252
253 Details.Children.Add(Button = new Button()
254 {
255 Margin = new Thickness(0, 6, 0, 6),
256 Content = "Yes, to anyone from " + s
257 });
258
259 Button.Click += this.YesDomainButton_Click;
260
261 Details.Children.Add(Button = new Button()
262 {
263 Margin = new Thickness(0, 6, 0, 6),
264 Content = "No, to no one from " + s
265 });
266
267 Button.Click += this.NoDomainButton_Click;
268 }
269
270 Details.Children.Add(Button = new Button()
271 {
272 Margin = new Thickness(0, 6, 0, 6),
273 Content = "Yes, to anyone"
274 });
275
276 Button.Click += this.YesAllButton_Click;
277
278 Details.Children.Add(Button = new Button()
279 {
280 Margin = new Thickness(0, 6, 0, 6),
281 Content = "No, to no one"
282 });
283
284 Button.Click += this.NoAllButton_Click;
285
286 this.AddTokens(Details, this.client, this.YesTokenButton_Click, this.NoTokenButton_Click);
287 }
288
289 internal static StackPanel AddAllClearButtons(StackPanel Details, ListBox ListBox)
290 {
291 StackPanel StackPanel;
292 Button Button;
293
294 Details.Children.Add(StackPanel = new StackPanel()
295 {
296 Orientation = Orientation.Horizontal,
297 HorizontalAlignment = HorizontalAlignment.Center
298 });
299
300 StackPanel.Children.Add(Button = new Button()
301 {
302 Margin = new Thickness(6, 6, 6, 6),
303 Padding = new Thickness(20, 0, 20, 0),
304 Content = "All",
305 Tag = ListBox
306 });
307
308 Button.Click += AllButton_Click;
309
310 StackPanel.Children.Add(Button = new Button()
311 {
312 Margin = new Thickness(6, 6, 6, 6),
313 Padding = new Thickness(20, 0, 20, 0),
314 Content = "Clear",
315 Tag = ListBox
316 });
317
318 Button.Click += ClearButton_Click;
319
320 return StackPanel;
321 }
322
323 internal static void ClearButton_Click(object Sender, RoutedEventArgs e)
324 {
325 if (Sender is Button Button && Button.Tag is ListBox ListBox)
326 {
327 foreach (ListBoxItem Item in ListBox.Items)
328 Item.IsSelected = false;
329 }
330 }
331
332 internal static void AllButton_Click(object Sender, RoutedEventArgs e)
333 {
334 if (Sender is Button Button && Button.Tag is ListBox ListBox)
335 {
336 foreach (ListBoxItem Item in ListBox.Items)
337 Item.IsSelected = true;
338 }
339 }
340
341 private async void GetListButton_Click(object Sender, RoutedEventArgs e)
342 {
343 try
344 {
345 XmppClient Client = this.client.Client;
346
347 ((Button)Sender).IsEnabled = false;
348
349 RosterItem Item = Client[this.JID];
350 if (Item is null || Item.State == SubscriptionState.None || Item.State == SubscriptionState.From)
351 {
352 if (!this.registered)
353 {
354 this.registered = true;
355 this.questionView.Owner.RegisterRosterEventHandler(this.JID, this.RosterItemUpdated);
356 }
357
358 await Client.RequestPresenceSubscription(this.JID);
359 }
360 else if (!Item.HasLastPresence || !Item.LastPresence.IsOnline)
361 await Client.RequestPresenceSubscription(this.JID);
362 else
363 await this.DoRequest(Item);
364 }
365 catch (Exception ex)
366 {
367 Log.Exception(ex);
368 }
369 }
370
371 public override void Dispose()
372 {
373 if (this.registered)
374 {
375 this.registered = false;
376 this.questionView.Owner.UnregisterRosterEventHandler(this.JID, this.RosterItemUpdated);
377 }
378
379 base.Dispose();
380 }
381
382 private async Task RosterItemUpdated(object Sender, RosterItem Item)
383 {
384 if ((Item.State == SubscriptionState.Both || Item.State == SubscriptionState.To) && Item.HasLastPresence && Item.LastPresence.IsOnline)
385 {
386 this.questionView.Owner.UnregisterRosterEventHandler(this.JID, this.RosterItemUpdated);
387 await this.DoRequest(Item);
388 }
389 }
390
391 private async Task DoRequest(RosterItem Item)
392 {
394
395 this.fieldsSorted = new SortedDictionary<string, bool>();
396
397 if (this.IsNode)
398 Request = await this.questionView.Owner.SensorClient.RequestReadout(Item.LastPresenceFullJid,
399 new ThingReference[] { this.GetNodeReference() }, FieldType.All);
400 else
401 Request = await this.questionView.Owner.SensorClient.RequestReadout(Item.LastPresenceFullJid, FieldType.All);
402
403 Request.OnStateChanged += this.Request_OnStateChanged;
404 Request.OnFieldsReceived += this.Request_OnFieldsReceived;
405 }
406
407 private async Task Request_OnStateChanged(object Sender, SensorDataReadoutState NewState)
408 {
409 if (NewState == SensorDataReadoutState.Done)
410 {
411 string[] Fields;
412
413 lock (this.fieldsSorted)
414 {
415 Fields = new string[this.fieldsSorted.Count];
416 this.fieldsSorted.Keys.CopyTo(Fields, 0);
417 }
418
419 this.availableFieldNames = Fields;
420 await Database.Update(this);
421
422 MainWindow.UpdateGui(() =>
423 {
424 SortedDictionary<string, bool> Selected = null;
425 bool AllSelected = this.fieldNames is null;
426
427 if (!AllSelected)
428 {
429 Selected = new SortedDictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
430
431 foreach (ListBoxItem Item in this.fieldsListBox.Items)
432 {
433 if (Item.IsSelected)
434 Selected[(string)Item.Tag] = true;
435 }
436 }
437
438 this.fieldsListBox.Items.Clear();
439
440 foreach (string FieldName in this.availableFieldNames)
441 {
442 this.fieldsListBox.Items.Add(new ListBoxItem()
443 {
444 Content = FieldName,
445 IsSelected = AllSelected || Selected.ContainsKey(FieldName),
446 Tag = FieldName
447 });
448 }
449
450 return Task.CompletedTask;
451 });
452 }
453 }
454
455 private Task Request_OnFieldsReceived(object _, IEnumerable<Field> NewFields)
456 {
457 lock (this.fieldsSorted)
458 {
459 foreach (Field F in NewFields)
460 this.fieldsSorted[F.Name] = true;
461 }
462
463 return Task.CompletedTask;
464 }
465
466 private FieldType GetFieldType()
467 {
468 FieldType Result = (FieldType)0;
469
470 foreach (ListBoxItem Item in this.typesListBox.Items)
471 {
472 if (Item.IsSelected)
473 Result |= (FieldType)Item.Tag;
474 }
475
476 return Result;
477 }
478
479 private string[] GetFields()
480 {
481 List<string> Result = new List<string>();
482 bool All = true;
483
484 foreach (ListBoxItem Item in this.fieldsListBox.Items)
485 {
486 if (Item.IsSelected)
487 Result.Add((string)Item.Tag);
488 else
489 All = false;
490 }
491
492 if (this.availableFieldNames is null || !All)
493 return Result.ToArray();
494 else
495 return null;
496 }
497
498 private async Task RuleCallback(object Sender, IqResultEventArgs e)
499 {
500 try
501 {
502 if (e.Ok)
503 await this.Processed(this.questionView);
504 else
505 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to set rule." : e.ErrorText);
506 }
507 catch (Exception ex)
508 {
509 ex = Log.UnnestException(ex);
510 MainWindow.ErrorBox(ex.Message);
511 }
512 }
513
514 private void NoAllButton_Click(object Sender, RoutedEventArgs e)
515 {
516 this.range = OperationRange.All;
517 this.client.CanReadResponseAll(this.Sender, this.JID, this.RemoteJID, this.Key, false, this.GetFieldType(), this.GetFields(), this.GetNodeReference(), this.RuleCallback, null);
518 }
519
520 private void YesAllButton_Click(object Sender, RoutedEventArgs e)
521 {
522 this.range = OperationRange.All;
523 this.client.CanReadResponseAll(this.Sender, this.JID, this.RemoteJID, this.Key, true, this.GetFieldType(), this.GetFields(), this.GetNodeReference(), this.RuleCallback, null);
524 }
525
526 private void NoDomainButton_Click(object Sender, RoutedEventArgs e)
527 {
528 this.range = OperationRange.Domain;
529 this.client.CanReadResponseDomain(this.Sender, this.JID, this.RemoteJID, this.Key, false, this.GetFieldType(), this.GetFields(), this.GetNodeReference(), this.RuleCallback, null);
530 }
531
532 private void YesDomainButton_Click(object Sender, RoutedEventArgs e)
533 {
534 this.range = OperationRange.Domain;
535 this.client.CanReadResponseDomain(this.Sender, this.JID, this.RemoteJID, this.Key, true, this.GetFieldType(), this.GetFields(), this.GetNodeReference(), this.RuleCallback, null);
536 }
537
538 private void NoButton_Click(object Sender, RoutedEventArgs e)
539 {
540 this.range = OperationRange.Caller;
541 this.client.CanReadResponseCaller(this.Sender, this.JID, this.RemoteJID, this.Key, false, this.GetFieldType(), this.GetFields(), this.GetNodeReference(), this.RuleCallback, null);
542 }
543
544 private void YesButton_Click(object Sender, RoutedEventArgs e)
545 {
546 this.range = OperationRange.Caller;
547 this.client.CanReadResponseCaller(this.Sender, this.JID, this.RemoteJID, this.Key, true, this.GetFieldType(), this.GetFields(), this.GetNodeReference(), this.RuleCallback, null);
548 }
549
550 private void NoTokenButton_Click(object Sender, RoutedEventArgs e)
551 {
552 this.TokenButtonClick(Sender, e, false);
553 }
554
555 private void TokenButtonClick(object Sender, RoutedEventArgs _, bool Result)
556 {
557 Button Button = (Button)Sender;
558 object[] P = (object[])Button.Tag;
559 this.parameter = (string)P[0];
560 this.range = (OperationRange)P[1];
561
562 switch (this.range)
563 {
564 case OperationRange.ServiceToken:
565 this.client.CanReadResponseService(this.Sender, this.JID, this.RemoteJID, this.Key, Result, this.GetFieldType(), this.GetFields(), this.parameter, this.GetNodeReference(), this.RuleCallback, null);
566 break;
567
568 case OperationRange.DeviceToken:
569 this.client.CanReadResponseDevice(this.Sender, this.JID, this.RemoteJID, this.Key, Result, this.GetFieldType(), this.GetFields(), this.parameter, this.GetNodeReference(), this.RuleCallback, null);
570 break;
571
572 case OperationRange.UserToken:
573 this.client.CanReadResponseUser(this.Sender, this.JID, this.RemoteJID, this.Key, Result, this.GetFieldType(), this.GetFields(), this.parameter, this.GetNodeReference(), this.RuleCallback, null);
574 break;
575 }
576 }
577
578 private void YesTokenButton_Click(object Sender, RoutedEventArgs e)
579 {
580 this.TokenButtonClick(Sender, e, true);
581 }
582
583 public override bool IsResolvedBy(Question Question)
584 {
586 {
587 if (this.JID != CanReadQuestion.JID)
588 return false;
589
590 switch (this.range)
591 {
592 case OperationRange.Caller:
593 return (this.RemoteJID == CanReadQuestion.RemoteJID);
594
595 case OperationRange.Domain:
596 return (IsFriendQuestion.GetDomain(this.RemoteJID) == IsFriendQuestion.GetDomain(CanReadQuestion.RemoteJID));
597
598 case OperationRange.All:
599 return true;
600
601 case OperationRange.ServiceToken:
602 return MatchesToken(this.parameter, CanReadQuestion.ServiceTokens);
603
604 case OperationRange.DeviceToken:
605 return MatchesToken(this.parameter, CanReadQuestion.DeviceTokens);
606
607 case OperationRange.UserToken:
608 return MatchesToken(this.parameter, CanReadQuestion.UserTokens);
609
610 default:
611 return false;
612 }
613 }
614 else
615 return false;
616 }
617
618 internal static bool MatchesToken(string Token, string[] Tokens)
619 {
620 if (!(Tokens is null))
621 {
622 foreach (string Token2 in Tokens)
623 {
624 if (Token == Token2)
625 return true;
626 }
627 }
628
629 return false;
630 }
631
632 }
633}
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 void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:818
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 CanReadResponseService(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on a service token.
Task CanReadResponseUser(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on a user token.
Task CanReadResponseAll(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, for all future requests.
Task CanReadResponseCaller(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on the JID of the caller.
Task CanReadResponseDomain(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on the domain of the caller.
Task CanReadResponseDevice(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on a device token.
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
Base class for all sensor data fields.
Definition: Field.cs:20
Contains a reference to a thing
SensorDataReadoutState
Sensor Data Readout States.
SubscriptionState
State of a presence subscription.
Definition: RosterItem.cs:16
FieldType
Field Type flags
Definition: FieldType.cs:10