Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
XmppAccountNode.cs
1using System;
2using System.Collections.Generic;
3using System.Threading.Tasks;
4using System.Windows;
5using System.Windows.Controls;
6using System.Windows.Media;
7using System.Windows.Media.Imaging;
8using System.Xml;
18using Waher.Content;
20using Waher.Events;
47
49{
50 public enum TransportMethod
51 {
52 TraditionalSocket = 0,
53 WS = 1,
54 BOSH = 2
55 }
56
61 {
62 private const string SensorGroupName = "Sensors";
63 private const string EventsGroupName = "Events";
64 private const string ActuatorGroupName = "Actuators";
65 private const string ConcentratorGroupName = "Concentrators";
66 private const string OtherGroupName = "Others";
67 private const string RemoteDesktopGroupName = "RDP";
68
69 private readonly Dictionary<string, RemoteDesktopView> activeViews = new Dictionary<string, RemoteDesktopView>();
70 private readonly LinkedList<KeyValuePair<DateTime, MessageEventArgs>> unhandledMessages = new LinkedList<KeyValuePair<DateTime, MessageEventArgs>>();
71 private readonly LinkedList<XmppComponent> components = new LinkedList<XmppComponent>();
72 private readonly Dictionary<string, List<EventHandlerAsync<RosterItem>>> rosterSubscriptions = new Dictionary<string, List<EventHandlerAsync<RosterItem>>>(StringComparer.CurrentCultureIgnoreCase);
73 private readonly Connections connections;
74 private EndpointSecurity e2eEncryption;
75 private XmppClient client;
76 private PepClient pepClient;
77 private SensorClient sensorClient;
78 private ControlClient controlClient;
79 private ConcentratorClient concentratorClient;
80 private SynchronizationClient synchronizationClient;
81 private MultiUserChatClient mucClient;
82 private RemoteDesktopClient rdpClient;
83 private XmppEventReceptor eventReceptor;
84 private Socks5Proxy socks5Proxy = null;
85 //private XmppServerlessMessaging p2pNetwork;
86 private DateTime connectionTimer = DateTime.MinValue;
87 private Exception lastError = null;
88 private TransportMethod transport = TransportMethod.TraditionalSocket;
89 private string host;
90 private string domain;
91 private string urlBindResource;
92 private int port;
93 private string account;
94 private string password;
95 private string passwordHash;
96 private string passwordHashMethod;
97 private bool trustCertificate;
98 private bool connected = false;
99 private bool supportsSearch = false;
100 private bool allowInsecureAuthentication = false;
101 private readonly bool supportsHashes = true;
102
117 public XmppAccountNode(Connections Connections, TreeNode Parent, string Host, TransportMethod Transport, int Port, string UrlBindResource,
118 string Account, string PasswordHash, string PasswordHashMethod, bool TrustCertificate, bool AllowInsecureAuthentication)
119 : base(Parent)
120 {
121 this.connections = Connections;
122 this.host = this.domain = Host;
123 this.transport = Transport;
124 this.port = Port;
125 this.urlBindResource = UrlBindResource;
126 this.account = Account;
127
128 if (string.IsNullOrEmpty(PasswordHashMethod))
129 {
130 this.password = PasswordHash;
131 this.passwordHash = string.Empty;
132 this.passwordHashMethod = string.Empty;
133 this.supportsHashes = false;
134 }
135 else
136 {
137 this.password = string.Empty;
138 this.passwordHash = PasswordHash;
139 this.passwordHashMethod = PasswordHashMethod;
140 this.supportsHashes = true;
141 }
142
143 this.trustCertificate = TrustCertificate;
144 this.allowInsecureAuthentication = AllowInsecureAuthentication;
145
146 this.Init();
147 }
148
150 : base(Parent)
151 {
152 this.connections = Connections;
153 this.host = XML.Attribute(E, "host");
154 this.transport = XML.Attribute(E, "transport", TransportMethod.TraditionalSocket);
155 this.urlBindResource = XML.Attribute(E, "urlBindResource");
156 this.domain = XML.Attribute(E, "domain", this.host);
157 this.port = XML.Attribute(E, "port", XmppCredentials.DefaultPort);
158 this.account = XML.Attribute(E, "account");
159 this.password = XML.Attribute(E, "password");
160 this.passwordHash = XML.Attribute(E, "passwordHash");
161 this.passwordHashMethod = XML.Attribute(E, "passwordHashMethod");
162 this.trustCertificate = XML.Attribute(E, "trustCertificate", false);
163 this.allowInsecureAuthentication = XML.Attribute(E, "allowInsecureAuthentication", false);
164 this.supportsHashes = XML.Attribute(E, "supportsHashes", true);
165
166 this.Init();
167 }
168
169 private void Init(params ISniffer[] Sniffers)
170 {
171 XmppCredentials Credentials = new XmppCredentials()
172 {
173 Host = this.host,
174 Port = this.port,
175 Account = this.account,
176 TrustServer = this.trustCertificate,
177 AllowPlain = this.allowInsecureAuthentication,
178 AllowCramMD5 = this.allowInsecureAuthentication,
179 AllowDigestMD5 = this.allowInsecureAuthentication
180 };
181
182 switch (this.transport)
183 {
184 case TransportMethod.BOSH:
185 case TransportMethod.WS:
186 Credentials.UriEndpoint = this.urlBindResource;
187 break;
188 }
189
190 if (!string.IsNullOrEmpty(this.passwordHash))
191 {
192 Credentials.Password = this.passwordHash;
193 Credentials.PasswordType = this.passwordHashMethod;
194 }
195 else
196 Credentials.Password = this.password;
197
198 this.client = new XmppClient(Credentials, "en", typeof(App).Assembly)
199 {
200 AllowQuickLogin = true,
201 };
202
203 if (!(Sniffers is null))
204 this.client.AddRange(Sniffers);
205
206 this.client.OnStateChanged += this.Client_OnStateChanged;
207 this.client.OnError += this.Client_OnError;
208 this.client.OnPresence += this.Client_OnPresence;
209 this.client.OnPresenceSubscribe += this.Client_OnPresenceSubscribe;
210 this.client.OnPresenceUnsubscribe += this.Client_OnPresenceUnsubscribe;
211 this.client.OnRosterItemAdded += this.Client_OnRosterItemUpdated;
212 this.client.OnRosterItemRemoved += this.Client_OnRosterItemRemoved;
213 this.client.OnRosterItemUpdated += this.Client_OnRosterItemUpdated;
214 this.connectionTimer = MainWindow.Scheduler.Add(DateTime.Now.AddMinutes(1), this.CheckConnection, null);
215 this.client.OnNormalMessage += this.Client_OnNormalMessage;
216 this.client.OnErrorMessage += this.Client_OnErrorMessage;
217
218 this.client.SetPresence(Availability.Chat);
219
220 this.sensorClient = new SensorClient(this.client);
221 this.controlClient = new ControlClient(this.client);
222 this.concentratorClient = new ConcentratorClient(this.client);
223 this.synchronizationClient = new SynchronizationClient(this.client);
224
225 this.eventReceptor = new XmppEventReceptor(this.client);
226 this.eventReceptor.OnEvent += this.EventReceptor_OnEvent;
227
228 this.AddPepClient(string.Empty);
229
230 this.concentratorClient.OnCustomSnifferMessage += this.ConcentratorClient_OnCustomSnifferMessage;
231 this.concentratorClient.OnEvent += this.ConcentratorClient_OnEvent;
232
233 //this.p2pNetwork = new XmppServerlessMessaging("RDP " + this.BareJID, this.client.BareJID);
234 //this.p2pNetwork.OnNewXmppClient += ServerlessMessaging_OnNewXmppClient;
235 //this.p2pNetwork.OnResynch += ServerlessMessaging_OnResynch;
236
237 this.e2eEncryption = new EndpointSecurity(this.client, /*this.p2pNetwork,*/ 128,
239 this.client.SetTag("E2E", this.e2eEncryption);
240
241 this.socks5Proxy = new Socks5Proxy(this.client); //, this.XmppAccountNode.E2E); TODO
242 this.socks5Proxy.OnOpen += this.Proxy_OnOpen;
243
244 this.rdpClient = new RemoteDesktopClient(this.client, this.e2eEncryption);
245
246 this.client.Connect();
247 }
248
249 private Task Client_OnErrorMessage(object _, MessageEventArgs e)
250 {
251 string Msg = e.ErrorText;
252 if (!string.IsNullOrEmpty(Msg))
253 MainWindow.ErrorBox(Msg);
254
255 return Task.CompletedTask;
256 }
257
258 private void AddPepClient(string PubSubComponentAddress)
259 {
260 this.pepClient?.Dispose();
261 this.pepClient = null;
262
263 this.pepClient = new PepClient(this.client, PubSubComponentAddress);
264
265 this.pepClient.OnUserActivity += this.PepClient_OnUserActivity;
266 this.pepClient.OnUserAvatarMetaData += this.PepClient_OnUserAvatarMetaData;
267 this.pepClient.OnUserLocation += this.PepClient_OnUserLocation;
268 this.pepClient.OnUserMood += this.PepClient_OnUserMood;
269 this.pepClient.OnUserTune += this.PepClient_OnUserTune;
270 this.pepClient.RegisterHandler(typeof(SensorData), this.PepClient_SensorData);
271 }
272
273 private void AddMucClient(string MucComponentAddress)
274 {
275 this.mucClient?.Dispose();
276 this.mucClient = null;
277
278 this.mucClient = new MultiUserChatClient(this.client, MucComponentAddress);
279 }
280
281 private Task EventReceptor_OnEvent(object _, EventEventArgs e)
282 {
283 MainWindow.UpdateGui(() =>
284 {
285 LogView View = MainWindow.currentInstance.GetLogView(e.FromBareJID);
286 View.Add(new LogItem(e.Event));
287 return Task.CompletedTask;
288 });
289
290 return Task.CompletedTask;
291 }
292
293 private async Task ConcentratorClient_OnCustomSnifferMessage(object _, CustomSnifferEventArgs e)
294 {
295 TaskCompletionSource<SnifferView> View = new TaskCompletionSource<SnifferView>();
296
297 MainWindow.UpdateGui(() =>
298 {
299 View.TrySetResult(MainWindow.currentInstance.GetSnifferView(null, e.FromBareJID, true));
300 return Task.CompletedTask;
301 });
302
303 SnifferView SnifferView = await View.Task;
304
305 e.Sniffer = SnifferView.Sniffer;
306 }
307
308 private async Task ConcentratorClient_OnEvent(object Sender, SourceEventMessageEventArgs EventMessage)
309 {
310 if (this.TryGetChild(EventMessage.FromBareJID, out TreeNode Child) &&
311 (Child is XmppConcentrator Concentrator))
312 {
313 await Concentrator.ConcentratorClient_OnEvent(Sender, EventMessage);
314 }
315 }
316
317 private Task Client_OnNormalMessage(object _, MessageEventArgs e)
318 {
319 DateTime Now = DateTime.Now;
320 DateTime Limit = Now.AddMinutes(-1);
321
322 lock (this.unhandledMessages)
323 {
324 this.unhandledMessages.AddLast(new KeyValuePair<DateTime, MessageEventArgs>(Now, e));
325
326 while (!(this.unhandledMessages.First is null) && this.unhandledMessages.First.Value.Key <= Limit)
327 this.unhandledMessages.RemoveFirst();
328 }
329
330 return Task.CompletedTask;
331 }
332
333 public IEnumerable<MessageEventArgs> GetUnhandledMessages(string LocalName, string Namespace)
334 {
335 LinkedList<MessageEventArgs> Result = new LinkedList<MessageEventArgs>();
336 LinkedListNode<KeyValuePair<DateTime, MessageEventArgs>> Loop, Next;
337 bool Found;
338
339 lock (this.unhandledMessages)
340 {
341 Loop = this.unhandledMessages.First;
342
343 while (!(Loop is null))
344 {
345 Next = Loop.Next;
346
347 Found = false;
348
349 foreach (XmlElement E in Loop.Value.Value.Message.ChildNodes)
350 {
351 if (E.LocalName == LocalName && E.NamespaceURI == Namespace)
352 {
353 Found = true;
354 break;
355 }
356 }
357
358 if (Found)
359 {
360 Result.AddLast(Loop.Value.Value);
361 this.unhandledMessages.Remove(Loop);
362 }
363
364 Loop = Next;
365 }
366 }
367
368 return Result;
369 }
370
371 private Task Client_OnError(object _, Exception Exception)
372 {
373 this.lastError = Exception;
374 return Task.CompletedTask;
375 }
376
377 private async Task Client_OnStateChanged(object _, XmppState NewState)
378 {
379 switch (NewState)
380 {
381 case XmppState.Connected:
382 this.connected = true;
383 this.lastError = null;
384
385 if (this.supportsHashes && string.IsNullOrEmpty(this.passwordHash))
386 {
387 this.passwordHash = this.client.PasswordHash;
388 this.passwordHashMethod = this.client.PasswordHashMethod;
389 this.connections.Modified = true;
390 }
391
392 if (this.domain != this.client.Domain)
393 {
394 this.domain = this.client.Domain;
395 this.connections.Modified = true;
396 }
397
398 this.CheckRoster();
399 this.SearchComponents();
400
401 //this.p2pNetwork.FullJid = this.client.FullJID;
402 break;
403
404 case XmppState.Offline:
405 bool ImmediateReconnect = this.connected;
406 this.connected = false;
407
408 if (ImmediateReconnect && !(this.client is null))
409 await this.client.Reconnect();
410 break;
411 }
412
413 this.OnUpdated();
414 }
415
416 public TransportMethod Transport => this.transport;
417 public string Host => this.host;
418 public int Port => this.port;
419 public string Account => this.account;
420 public string PasswordHash => this.passwordHash;
421 public string PasswordHashMethod => this.passwordHashMethod;
422 public bool TrustCertificate => this.trustCertificate;
423 public bool AllowInsecureAuthentication => this.allowInsecureAuthentication;
424 public bool SupportsHashes => this.supportsHashes;
425
426 public override string Header
427 {
428 get { return this.account + "@" + this.domain; }
429 }
430
431 public override string TypeName
432 {
433 get { return "XMPP Account"; }
434 }
435
436 public override void Dispose()
437 {
438 base.Dispose();
439
440 if (this.connectionTimer > DateTime.MinValue)
441 {
442 MainWindow.Scheduler?.Remove(this.connectionTimer);
443 this.connectionTimer = DateTime.MinValue;
444 }
445
446 this.rdpClient?.Dispose();
447 this.rdpClient = null;
448
449 this.pepClient?.Dispose();
450 this.pepClient = null;
451
452 this.mucClient?.Dispose();
453 this.mucClient = null;
454
455 this.sensorClient?.Dispose();
456 this.sensorClient = null;
457
458 this.controlClient?.Dispose();
459 this.controlClient = null;
460
461 this.concentratorClient?.Dispose();
462 this.concentratorClient = null;
463
464 this.synchronizationClient?.Dispose();
465 this.synchronizationClient = null;
466
467 this.e2eEncryption?.Dispose();
468 this.e2eEncryption = null;
469
470 this.eventReceptor?.Dispose();
471 this.eventReceptor = null;
472
473 if (!(this.client is null))
474 {
475 this.client.RemoveTag("E2E");
476
477 XmppClient Client = this.client;
478 this.client = null;
479 Client.OfflineAndDisposeAsync().Wait(); // TODO: Asynchronous
480 }
481 }
482
483 private async void CheckConnection(object P)
484 {
485 try
486 {
487 this.connectionTimer = MainWindow.Scheduler.Add(DateTime.Now.AddMinutes(1), this.CheckConnection, null);
488
489 if (!(this.client is null) && (this.client.State == XmppState.Offline || this.client.State == XmppState.Error || this.client.State == XmppState.Authenticating))
490 await this.client.Reconnect();
491 }
492 catch (Exception ex)
493 {
494 MessageBox.Show(MainWindow.currentInstance, ex.Message, "Unable to reconnect.", MessageBoxButton.OK, MessageBoxImage.Error);
495 }
496 }
497
498 public override void Write(XmlWriter Output)
499 {
500 Output.WriteStartElement("XmppAccount");
501 Output.WriteAttributeString("host", this.host);
502 Output.WriteAttributeString("domain", this.domain);
503 Output.WriteAttributeString("transport", this.transport.ToString());
504 Output.WriteAttributeString("port", this.port.ToString());
505 Output.WriteAttributeString("urlBindResource", this.urlBindResource);
506
507 Output.WriteAttributeString("account", this.account);
508
509 if (string.IsNullOrEmpty(this.passwordHash))
510 Output.WriteAttributeString("password", this.password);
511 else
512 {
513 Output.WriteAttributeString("passwordHash", this.passwordHash);
514 Output.WriteAttributeString("passwordHashMethod", this.passwordHashMethod);
515 }
516
517 Output.WriteAttributeString("trustCertificate", CommonTypes.Encode(this.trustCertificate));
518 Output.WriteAttributeString("allowInsecureAuthentication", CommonTypes.Encode(this.allowInsecureAuthentication));
519
520 if (!this.supportsHashes)
521 Output.WriteAttributeString("supportsHashes", CommonTypes.Encode(this.supportsHashes));
522
523 Output.WriteEndElement();
524 }
525
526 internal static readonly BitmapImage away = new BitmapImage(new Uri("../Graphics/Away.png", UriKind.Relative));
527 internal static readonly BitmapImage busy = new BitmapImage(new Uri("../Graphics/DoNotDisturb.png", UriKind.Relative));
528 internal static readonly BitmapImage chat = new BitmapImage(new Uri("../Graphics/Chat.png", UriKind.Relative));
529 internal static readonly BitmapImage extendedAway = new BitmapImage(new Uri("../Graphics/ExtendedAway.png", UriKind.Relative));
530 internal static readonly BitmapImage offline = new BitmapImage(new Uri("../Graphics/Offline.png", UriKind.Relative));
531 internal static readonly BitmapImage online = new BitmapImage(new Uri("../Graphics/Online.png", UriKind.Relative));
532 internal static readonly BitmapImage folderBlueClosed = new BitmapImage(new Uri("../Graphics/folder-blue-icon.png", UriKind.Relative));
533 internal static readonly BitmapImage folderBlueOpen = new BitmapImage(new Uri("../Graphics/folder-blue-open-icon.png", UriKind.Relative));
534 internal static readonly BitmapImage folderYellowClosed = new BitmapImage(new Uri("../Graphics/folder-yellow-icon.png", UriKind.Relative));
535 internal static readonly BitmapImage folderYellowOpen = new BitmapImage(new Uri("../Graphics/folder-yellow-open-icon.png", UriKind.Relative));
536 internal static readonly BitmapImage box = new BitmapImage(new Uri("../Graphics/App-miscellaneous-icon.png", UriKind.Relative));
537 internal static readonly BitmapImage hourglass = new BitmapImage(new Uri("../Graphics/hourglass-icon.png", UriKind.Relative));
538 internal static readonly BitmapImage database = new BitmapImage(new Uri("../Graphics/Database-icon_16.png", UriKind.Relative));
539 internal static readonly BitmapImage component = new BitmapImage(new Uri("../Graphics/server-components-icon_16.png", UriKind.Relative));
540 internal static readonly BitmapImage chatBubble = new BitmapImage(new Uri("../Graphics/Chat-icon_16.png", UriKind.Relative));
541 internal static readonly BitmapImage legal = new BitmapImage(new Uri("../Graphics/justice-balance-icon_16.png", UriKind.Relative));
542 internal static readonly BitmapImage log = new BitmapImage(new Uri("../Graphics/App-edit-icon_16.png", UriKind.Relative));
543 internal static readonly BitmapImage none = new BitmapImage(new Uri("../Graphics/None.png", UriKind.Relative));
544 internal static readonly BitmapImage from = new BitmapImage(new Uri("../Graphics/From.png", UriKind.Relative));
545 internal static readonly BitmapImage to = new BitmapImage(new Uri("../Graphics/To.png", UriKind.Relative));
546 internal static readonly BitmapImage both = new BitmapImage(new Uri("../Graphics/Both.png", UriKind.Relative));
547
548 public override ImageSource ImageResource
549 {
550 get
551 {
552 if (this.client is null)
553 return offline;
554 else
555 {
556 switch (this.client.State)
557 {
558 case XmppState.Connected:
559 return online;
560
561 case XmppState.Error:
562 return busy;
563
564 case XmppState.Offline:
565 default:
566 return offline;
567 }
568 }
569 }
570 }
571
572 public override string ToolTip
573 {
574 get
575 {
576 switch (this.client.State)
577 {
578 case XmppState.Offline:
579 default:
580 return "Offline";
581
582 case XmppState.Connecting:
583 return "Connecting to broker.";
584
585 case XmppState.StreamNegotiation:
586 return "Performing Stream Negotiation.";
587
588 case XmppState.StreamOpened:
589 return "Stream Opened.";
590
591 case XmppState.StartingEncryption:
592 return "Switching to encrypted channel.";
593
594 case XmppState.Authenticating:
595 return "Performing user authentication.";
596
597 case XmppState.Registering:
598 return "Registering user account.";
599
600 case XmppState.Binding:
601 return "Performing session binding.";
602
603 case XmppState.FetchingRoster:
604 return "Fetching roster.";
605
606 case XmppState.SettingPresence:
607 return "Setting presence.";
608
609 case XmppState.Connected:
610 return "Connected.";
611
612 case XmppState.Error:
613 if (this.lastError is null)
614 return "In an error state.";
615 else
616 return this.lastError.Message;
617 }
618 }
619 }
620
621 public override bool CanAddChildren
622 {
623 get
624 {
625 return !(this.client is null) && this.client.State == XmppState.Connected;
626 }
627 }
628
629 public override bool CanEdit => true;
630 public override bool CanDelete => true;
631
632 public override void Add()
633 {
634 AddContactForm Dialog = new AddContactForm()
635 {
636 Owner = this.connections.Owner
637 };
638
639 bool? Result = Dialog.ShowDialog();
640
641 if (Result.HasValue && Result.Value)
642 this.client.RequestPresenceSubscription(Dialog.ContactJID.Text);
643 }
644
645 private void CheckRoster()
646 {
647 SortedDictionary<string, TreeNode> Contacts = this.children;
648 Dictionary<string, TreeNode> Existing = new Dictionary<string, TreeNode>();
649 LinkedList<TreeNode> Added = null;
650 LinkedList<KeyValuePair<string, TreeNode>> Removed = null;
651 LinkedList<RosterItem> Resubscribe = null;
652 LinkedList<RosterItem> Reunsubscribe = null;
653
654 if (Contacts is null)
655 Contacts = new SortedDictionary<string, TreeNode>();
656
657 lock (Contacts)
658 {
659 foreach (RosterItem Item in this.client.Roster)
660 {
661 if (Contacts.TryGetValue(Item.BareJid, out TreeNode Contact))
662 Existing[Item.BareJid] = Contact;
663 else
664 {
665 if (Item.IsInGroup(ConcentratorGroupName))
666 Contact = new XmppConcentrator(this, this.client, Item.BareJid, Item.IsInGroup(EventsGroupName), Item.IsInGroup(RemoteDesktopGroupName));
667 else if (Item.IsInGroup(ActuatorGroupName))
668 Contact = new XmppActuator(this, this.client, Item.BareJid, Item.IsInGroup(SensorGroupName), Item.IsInGroup(EventsGroupName), Item.IsInGroup(RemoteDesktopGroupName));
669 else if (Item.IsInGroup(SensorGroupName))
670 Contact = new XmppSensor(this, this.client, Item.BareJid, Item.IsInGroup(EventsGroupName), Item.IsInGroup(RemoteDesktopGroupName));
671 else if (Item.IsInGroup(OtherGroupName))
672 Contact = new XmppOther(this, this.client, Item.BareJid, Item.IsInGroup(RemoteDesktopGroupName));
673 else
674 Contact = new XmppContact(this, this.client, Item.BareJid, Item.IsInGroup(RemoteDesktopGroupName));
675
676 Contacts[Item.BareJid] = Contact;
677
678 if (Added is null)
679 Added = new LinkedList<TreeNode>();
680
681 Added.AddLast(Contact);
682 }
683
684 switch (Item.PendingSubscription)
685 {
686 case PendingSubscription.Subscribe:
687 if (Resubscribe is null)
688 Resubscribe = new LinkedList<RosterItem>();
689
690 Resubscribe.AddLast(Item);
691 break;
692
693 case PendingSubscription.Unsubscribe:
694 if (Reunsubscribe is null)
695 Reunsubscribe = new LinkedList<RosterItem>();
696
697 Reunsubscribe.AddLast(Item);
698 break;
699 }
700 }
701
702 if (this.children is null)
703 this.children = Contacts;
704 else
705 {
706 foreach (KeyValuePair<string, TreeNode> P in this.children)
707 {
708 if (P.Value is XmppContact Contact &&
709 !Existing.ContainsKey(Contact.BareJID))
710 {
711 if (Removed is null)
712 Removed = new LinkedList<KeyValuePair<string, TreeNode>>();
713
714 Removed.AddLast(P);
715 }
716 }
717
718 if (!(Removed is null))
719 {
720 foreach (KeyValuePair<string, TreeNode> P in Removed)
721 this.children.Remove(P.Key);
722 }
723 }
724 }
725
726 if (!(Added is null))
727 {
728 foreach (TreeNode Node in Added)
729 this.connections.Owner.MainView.NodeAdded(this, Node);
730 }
731
732 if (!(Removed is null))
733 {
734 foreach (KeyValuePair<string, TreeNode> P in Removed)
735 this.connections.Owner.MainView.NodeRemoved(this, P.Value);
736 }
737
738 if (!(Resubscribe is null))
739 {
740 foreach (RosterItem Item in Resubscribe)
741 this.client.RequestPresenceSubscription(Item.BareJid);
742 }
743
744 if (!(Reunsubscribe is null))
745 {
746 foreach (RosterItem Item in Reunsubscribe)
747 this.client.RequestPresenceUnsubscription(Item.BareJid);
748 }
749
750 this.OnUpdated();
751 }
752
753 public Controls.ConnectionView View
754 {
755 get { return this.connections.Owner.MainView; }
756 }
757
758 private async Task Client_OnRosterItemUpdated(object _, RosterItem Item)
759 {
760 if (this.children is null)
761 this.CheckRoster();
762 else
763 {
764 XmppContact Contact;
765 bool Added = false;
766
767 lock (this.children)
768 {
769 if (this.children.TryGetValue(Item.BareJid, out TreeNode Node))
770 {
771 if (!((Contact = Node as XmppContact) is null))
772 Contact.RosterItem = Item;
773 }
774 else
775 {
776 Contact = new XmppContact(this, this.client, Item.BareJid, Item.IsInGroup(RemoteDesktopGroupName));
777 this.children[Item.BareJid] = Contact;
778 Added = true;
779 }
780 }
781
782 if (Added)
783 {
784 this.connections.Owner.MainView.NodeAdded(this, Contact);
785 this.OnUpdated();
786 }
787 else
788 Contact.OnUpdated();
789
790 await this.CheckRosterItemSubscriptions(Item);
791 }
792 }
793
794 private async Task CheckRosterItemSubscriptions(RosterItem Item)
795 {
796 EventHandlerAsync<RosterItem>[] h;
797
798 lock (this.rosterSubscriptions)
799 {
800 if (this.rosterSubscriptions.TryGetValue(Item.BareJid, out List<EventHandlerAsync<RosterItem>> List))
801 h = List.ToArray();
802 else
803 h = null;
804 }
805
806 if (!(h is null))
807 {
808 foreach (EventHandlerAsync<RosterItem> h2 in h)
809 await h2.Raise(this, Item);
810 }
811 }
812
813 public void RegisterRosterEventHandler(string BareJid, EventHandlerAsync<RosterItem> Callback)
814 {
815 lock (this.rosterSubscriptions)
816 {
817 if (!this.rosterSubscriptions.TryGetValue(BareJid, out List<EventHandlerAsync<RosterItem>> h))
818 {
819 h = new List<EventHandlerAsync<RosterItem>>();
820 this.rosterSubscriptions[BareJid] = h;
821 }
822
823 h.Add(Callback);
824 }
825 }
826
827 public void UnregisterRosterEventHandler(string BareJid, EventHandlerAsync<RosterItem> Callback)
828 {
829 lock (this.rosterSubscriptions)
830 {
831 if (this.rosterSubscriptions.TryGetValue(BareJid, out List<EventHandlerAsync<RosterItem>> h) && h.Remove(Callback) && h.Count == 0)
832 this.rosterSubscriptions.Remove(BareJid);
833 }
834 }
835
836 private Task Client_OnRosterItemRemoved(object _, RosterItem Item)
837 {
838 if (this.children is null)
839 this.CheckRoster();
840 else
841 {
842 bool Updated;
843
844 lock (this.children)
845 {
846 Updated = this.children.Remove(Item.BareJid);
847 }
848
849 this.OnUpdated();
850 }
851
852 return Task.CompletedTask;
853 }
854
855 private async Task Client_OnPresence(object _, PresenceEventArgs e)
856 {
857 if (this.children is null)
858 this.CheckRoster();
859 else
860 {
862
863 lock (this.children)
864 {
865 if (!this.children.TryGetValue(e.FromBareJID, out Node))
866 Node = null;
867 }
868
869 if (!(Node is null))
870 {
871 Node.OnUpdated();
872
873 if (e.Availability != Availability.Offline && Node.GetType() == typeof(XmppContact))
874 this.CheckType(Node, e.From);
875 }
876 else if (string.Compare(e.FromBareJID, this.client.BareJID, true) == 0)
877 await this.client.Information("Presence from same bare JID. Ignored.");
878 else
879 await this.client.Warning("Presence from node not found in roster: " + e.FromBareJID);
880
881 RosterItem Item = this.client?.GetRosterItem(e.FromBareJID);
882 if (!(Item is null))
883 await this.CheckRosterItemSubscriptions(Item);
884 }
885 }
886
887 internal void CheckType(TreeNode Node, string FullJid)
888 {
889 this.client.SendServiceDiscoveryRequest(FullJid, this.ServiceDiscoveryResponse, Node);
890 }
891
892 private Task ServiceDiscoveryResponse(object _, ServiceDiscoveryEventArgs e)
893 {
894 if (e.Ok)
895 {
897 object OldTag;
898
900 {
901 bool SupportsEvents = e.HasAnyFeature(SensorClient.NamespacesSensorEvents);
903
904 OldTag = Node.Tag;
905 Node = new XmppConcentrator(Node.Parent, this.client, Node.BareJID, SupportsEvents, SupportsRdp)
906 {
907 Tag = OldTag
908 };
909
910 this.children[Node.Key] = Node;
911
912 List<string> Groups = new List<string>()
913 {
914 ConcentratorGroupName
915 };
916
917 if (SupportsEvents)
918 Groups.Add(EventsGroupName);
919
920 if (SupportsRdp)
921 Groups.Add(RemoteDesktopGroupName);
922
923 this.AddGroups(Node, Groups.ToArray());
924 }
926 {
928 bool SupportsEvents = e.HasAnyFeature(SensorClient.NamespacesSensorEvents);
930
931 OldTag = Node.Tag;
932 Node = new XmppActuator(Node.Parent, this.client, Node.BareJID, IsSensor, SupportsEvents, SupportsRdp)
933 {
934 Tag = OldTag
935 };
936
937 this.children[Node.Key] = Node;
938
939 List<string> Groups = new List<string>()
940 {
941 ActuatorGroupName
942 };
943
944 if (IsSensor)
945 Groups.Add(SensorGroupName);
946
947 if (SupportsEvents)
948 Groups.Add(EventsGroupName);
949
950 if (SupportsRdp)
951 Groups.Add(RemoteDesktopGroupName);
952
953 this.AddGroups(Node, Groups.ToArray());
954 }
956 {
957 bool SupportsEvents = e.HasAnyFeature(SensorClient.NamespacesSensorEvents);
959
960 OldTag = Node.Tag;
961 Node = new XmppSensor(Node.Parent, this.client, Node.BareJID, SupportsEvents, SupportsRdp)
962 {
963 Tag = OldTag
964 };
965
966 this.children[Node.Key] = Node;
967
968 List<string> Groups = new List<string>()
969 {
970 SensorGroupName
971 };
972
973 if (SupportsEvents)
974 Groups.Add(EventsGroupName);
975
976 if (SupportsRdp)
977 Groups.Add(RemoteDesktopGroupName);
978
979 this.AddGroups(Node, Groups.ToArray());
980 }
981 else
982 {
984
985 OldTag = Node.Tag;
986 Node = new XmppOther(Node.Parent, this.client, Node.BareJID, SupportsRdp)
987 {
988 Tag = OldTag
989 };
990
991 this.children[Node.Key] = Node;
992
993 List<string> Groups = new List<string>()
994 {
995 OtherGroupName
996 };
997
998 if (SupportsRdp)
999 Groups.Add(RemoteDesktopGroupName);
1000
1001 this.AddGroups(Node, Groups.ToArray());
1002 }
1003
1004 this.OnUpdated();
1005 }
1006
1007 return Task.CompletedTask;
1008 }
1009
1010 private void AddGroups(XmppContact Contact, params string[] GroupNames)
1011 {
1012 string[] Groups = Contact.RosterItem.Groups;
1013 bool Updated = false;
1014 int c;
1015
1016 foreach (string GroupName in GroupNames)
1017 {
1018 if (Array.IndexOf<string>(Groups, GroupName) < 0)
1019 {
1020 c = Groups.Length;
1021 Array.Resize<string>(ref Groups, c + 1);
1022 Groups[c] = GroupName;
1023
1024 Updated = true;
1025 }
1026 }
1027
1028 if (Updated)
1029 {
1030 Array.Sort<string>(Groups);
1031 this.client.UpdateRosterItem(Contact.BareJID, Contact.RosterItem.Name, Groups);
1032 }
1033 }
1034
1035 private async Task Client_OnPresenceSubscribe(object _, PresenceEventArgs e)
1036 {
1038
1039 if (!(Item is null) && (Item.State == SubscriptionState.Both || Item.State == SubscriptionState.From))
1040 await e.Accept();
1041 else
1042 MainWindow.UpdateGui(this.PresenceSubscribe, e);
1043 }
1044
1045 private async Task PresenceSubscribe(object P)
1046 {
1048
1049 switch (MessageBox.Show(this.connections.Owner, e.FromBareJID + " has requested to subscribe to your presence (become your friend). Do you accept?",
1050 this.client.BareJID, MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Yes))
1051 {
1052 case MessageBoxResult.Yes:
1053 await e.Accept();
1054
1055 RosterItem Item = this.client.GetRosterItem(e.FromBareJID);
1056 if (Item is null || Item.State == SubscriptionState.None || Item.State == SubscriptionState.From)
1057 await this.client.RequestPresenceSubscription(e.FromBareJID);
1058
1059 await this.client.SetPresence(Availability.Chat);
1060 break;
1061
1062 case MessageBoxResult.No:
1063 await e.Decline();
1064 break;
1065
1066 case MessageBoxResult.Cancel:
1067 default:
1068 // Do nothing.
1069 break;
1070 }
1071 }
1072
1073 private Task Client_OnPresenceUnsubscribe(object _, PresenceEventArgs e)
1074 {
1075 return e.Accept();
1076 }
1077
1078 public override bool CanRecycle
1079 {
1080 get { return !(this.client is null); }
1081 }
1082
1083 public override async Task Recycle(MainWindow Window)
1084 {
1085 if (!(this.children is null))
1086 {
1087 foreach (TreeNode Node in this.children.Values)
1088 {
1089 if (Node.CanRecycle)
1090 await Node.Recycle(Window);
1091 }
1092 }
1093
1094 await this.client.Reconnect();
1095 }
1096
1097 public bool IsOnline
1098 {
1099 get
1100 {
1101 return !(this.client is null) && this.client.State == XmppState.Connected;
1102 }
1103 }
1104
1105 public string BareJID
1106 {
1107 get
1108 {
1109 if (this.client is null)
1110 return string.Empty;
1111 else
1112 return this.client.BareJID;
1113 }
1114 }
1115
1116 public override string Key => this.BareJID;
1117 public override bool IsSniffable => !(this.client is null);
1118 public XmppClient Client => this.client;
1119 //public XmppServerlessMessaging P2P => this.p2pNetwork;
1120 public EndpointSecurity E2E => this.e2eEncryption;
1121 public PepClient PepClient => this.pepClient;
1122 public MultiUserChatClient MucClient => this.mucClient;
1123 public SensorClient SensorClient => this.sensorClient;
1124 public ControlClient ControlClient => this.controlClient;
1125 public ConcentratorClient ConcentratorClient => this.concentratorClient;
1126 public SynchronizationClient SynchronizationClient => this.synchronizationClient;
1127 public RemoteDesktopClient RdpClient => this.rdpClient;
1128
1129 public override bool RemoveChild(TreeNode Node)
1130 {
1131 if (base.RemoveChild(Node))
1132 {
1133 if (Node is XmppContact Contact)
1134 {
1135 try
1136 {
1137 this.client.RemoveRosterItem(Contact.BareJID);
1138 }
1139 catch (ArgumentException)
1140 {
1141 // Already removed.
1142 }
1143 }
1144
1145 return true;
1146 }
1147 else
1148 return false;
1149 }
1150
1151 public override void AddSniffer(Networking.Sniffers.ISniffer Sniffer)
1152 {
1153 this.client.Add(Sniffer);
1154 }
1155
1156 public override Task<bool> RemoveSniffer(ISniffer Sniffer)
1157 {
1158 if (this.client is null)
1159 return Task.FromResult(false);
1160 else
1161 return Task.FromResult(this.client.Remove(Sniffer));
1162 }
1163
1164 public override void Added(MainWindow Window)
1165 {
1166 this.client.OnChatMessage += Window.OnChatMessage;
1167 this.client.OnStateChanged += Window.OnStateChange;
1168 }
1169
1170 public override void Removed(MainWindow Window)
1171 {
1172 this.client.OnChatMessage -= Window.OnChatMessage;
1173 this.client.OnStateChanged -= Window.OnStateChange;
1174 }
1175
1176 public void SearchComponents()
1177 {
1178 this.client.SendServiceDiscoveryRequest(this.client.Domain, (Sender, e) =>
1179 {
1180 this.supportsSearch = e.HasFeature(XmppClient.NamespaceSearch);
1181
1182 if (!this.supportsSearch)
1183 {
1184 this.client.SendSearchFormRequest(string.Empty, (sender2, e2) =>
1185 {
1186 if (e2.Ok)
1187 this.supportsSearch = true;
1188
1189 return Task.CompletedTask;
1190
1191 }, null, null);
1192 }
1193
1194 return Task.CompletedTask;
1195
1196 }, null);
1197
1198 this.client.SendServiceItemsDiscoveryRequest(this.client.Domain, (Sender, e) =>
1199 {
1200 foreach (Item Item in e.Items)
1201 {
1202 this.client.SendServiceDiscoveryRequest(Item.JID, async (sender2, e2) =>
1203 {
1204 try
1205 {
1206 XmppComponent Component = null;
1207 ThingRegistry ThingRegistry = null;
1208
1209 if (this.children is null)
1210 this.children = new SortedDictionary<string, TreeNode>();
1211
1212 lock (this.children)
1213 {
1214 if (this.children.ContainsKey(Item.JID))
1215 return;
1216 }
1217
1218 if (e2.HasAnyFeature(ThingRegistryClient.NamespacesDiscovery))
1219 {
1220 ThingRegistry = new ThingRegistry(this, Item.JID, Item.Name, Item.Node, e2.Features);
1221 Component = ThingRegistry;
1222 }
1223 else if (e2.HasFeature(PubSubClient.NamespacePubSub))
1224 {
1225 this.AddPepClient(Item.JID);
1226 Component = new PubSubService(this, Item.JID, Item.Name, Item.Node, e2.Features, this.pepClient.PubSubClient);
1227 }
1228 else if (e2.HasFeature(MultiUserChatClient.NamespaceMuc))
1229 {
1230 this.AddMucClient(Item.JID);
1231 Component = new MucService(this, Item.JID, Item.Name, Item.Node, e2.Features, this.mucClient);
1232 }
1233 else if (e2.HasAnyFeature(ContractsClient.NamespacesLegalIdentities))
1234 Component = await LegalService.Create(this, Item.JID, Item.Name, Item.Node, e2.Features);
1235 else if (e2.HasFeature(EventLog.NamespaceEventLogging))
1236 Component = new EventLog(this, Item.JID, Item.Name, Item.Node, e2.Features);
1237 else
1238 Component = new XmppComponent(this, Item.JID, Item.Name, Item.Node, e2.Features);
1239
1240 lock (this.children)
1241 {
1242 if (this.children.ContainsKey(Item.JID))
1243 {
1244 Component.Dispose();
1245 return;
1246 }
1247
1248 this.children[Item.JID] = Component;
1249 }
1250
1251 this.connections.Owner.MainView.NodeAdded(this, Component);
1252 this.OnUpdated();
1253
1254 if (!(ThingRegistry is null) && ThingRegistry.SupportsProvisioning)
1255 {
1256 MainWindow.UpdateGui(() =>
1257 {
1258 MainWindow.currentInstance.NewQuestion(this, ThingRegistry.ProvisioningClient, null);
1259 return Task.CompletedTask;
1260 });
1261 }
1262 }
1263 catch (Exception ex)
1264 {
1265 Log.Exception(ex);
1266 }
1267
1268 }, null);
1269 }
1270
1271 return Task.CompletedTask;
1272
1273 }, null);
1274 }
1275
1276 public override bool CanConfigure => this.IsOnline;
1277
1278 public override async Task GetConfigurationForm(EventHandlerAsync<DataFormEventArgs> Callback, object State)
1279 {
1280 DataForm Form = new DataForm(this.client, this.ChangePassword, this.CancelChangePassword, this.BareJID, this.BareJID,
1281 new TextPrivateField(null, "Password", "New password:", true, new string[] { string.Empty }, null,
1282 "Enter new password here.", new StringDataType(), new PasswordValidation(), string.Empty, false, false, false),
1283 new TextPrivateField(null, "Password2", "Retype password:", true, new string[] { string.Empty }, null,
1284 "Retype password here.", new StringDataType(), new Password2Validation(), string.Empty, false, false, false))
1285 {
1286 Title = "Change password",
1287 Instructions = new string[] { "Enter the new password you wish to use." }
1288 };
1289
1290 await Callback.Raise(this, new DataFormEventArgs(Form, new IqResultEventArgs(null, string.Empty, this.BareJID, this.BareJID, true, State)));
1291 }
1292
1293 private class PasswordValidation : BasicValidation
1294 {
1295 public override void Validate(Networking.XMPP.DataForms.Field Field, DataType DataType, object[] Parsed, string[] Strings)
1296 {
1297 string Password = Strings[0];
1298
1299 if (Password.Length < 6)
1300 Field.Error = "Password too short.";
1301 else
1302 {
1303 bool Digits = false;
1304 bool Lower = false;
1305 bool Upper = false;
1306
1307 foreach (char ch in Password)
1308 {
1309 Digits |= char.IsDigit(ch);
1310 Lower |= char.IsLower(ch);
1311 Upper |= char.IsUpper(ch);
1312 }
1313
1314 if (!Digits)
1315 Field.Error = "Password must contain digits.";
1316 else if (!Lower)
1317 Field.Error = "Password must contain lower case characters.";
1318 else if (!Upper)
1319 Field.Error = "Password must contain upper case characters.";
1320 }
1321 }
1322 }
1323
1324 private class Password2Validation : BasicValidation
1325 {
1326 public override void Validate(Networking.XMPP.DataForms.Field Field, DataType DataType, object[] Parsed, string[] Strings)
1327 {
1328 string Password = Strings[0];
1329
1330 if (Password != Field.Form["Password"].ValueString)
1331 Field.Error = "Passwords don't match.";
1332 }
1333 }
1334
1335 private Task ChangePassword(object _, DataForm Form)
1336 {
1337 string NewPassword = Form["Password"].ValueString;
1338
1339 this.client.ChangePassword(NewPassword, (Sender, e) =>
1340 {
1341 if (e.Ok)
1342 {
1343 this.connections.Modified = true;
1344 this.passwordHash = string.Empty;
1345 this.client.Reconnect(this.client.UserName, NewPassword);
1346
1347 MainWindow.SuccessBox("Password successfully changed.");
1348 }
1349 else
1350 MainWindow.ErrorBox("Unable to change password.");
1351
1352 return Task.CompletedTask;
1353
1354 }, null);
1355
1356 return Task.CompletedTask;
1357 }
1358
1359 private Task CancelChangePassword(object _, DataForm _2)
1360 {
1361 // Do nothing.
1362 return Task.CompletedTask;
1363 }
1364
1365 public override bool CanReadSensorData => this.IsOnline;
1366
1367 public override Task<SensorDataClientRequest> StartSensorDataFullReadout()
1368 {
1369 return this.DoReadout(FieldType.All);
1370 }
1371
1372 public override Task<SensorDataClientRequest> StartSensorDataMomentaryReadout()
1373 {
1374 return this.DoReadout(FieldType.Momentary);
1375 }
1376
1377 private async Task<SensorDataClientRequest> DoReadout(FieldType Types)
1378 {
1379 string Id = Guid.NewGuid().ToString();
1380
1381 CustomSensorDataClientRequest Request = new CustomSensorDataClientRequest(Id, string.Empty, string.Empty, null,
1382 Types, null, DateTime.MinValue, DateTime.MaxValue, DateTime.Now, string.Empty, string.Empty, string.Empty);
1383
1384 await Request.Accept(false);
1385 await Request.Started();
1386
1387 await this.client.SendServiceDiscoveryRequest(string.Empty, (Sender, e) =>
1388 {
1389 if (e.Ok)
1390 {
1391 List<Waher.Things.SensorData.Field> Fields = new List<Waher.Things.SensorData.Field>();
1392 DateTime Now = DateTime.Now;
1393
1394 foreach (KeyValuePair<string, bool> Feature in e.Features)
1395 {
1396 Fields.Add(new Waher.Things.SensorData.BooleanField(Waher.Things.ThingReference.Empty, Now,
1397 Feature.Key, Feature.Value, FieldType.Momentary, FieldQoS.AutomaticReadout));
1398 }
1399
1400 bool VersionDone = false;
1401
1402 if ((Types & FieldType.Identity) != 0)
1403 {
1404 foreach (Identity Identity in e.Identities)
1405 {
1406 Fields.Add(new StringField(Waher.Things.ThingReference.Empty, Now,
1407 Identity.Type, Identity.Category + (string.IsNullOrEmpty(Identity.Name) ? string.Empty : " (" + Identity.Name + ")"),
1408 FieldType.Identity,
1409 FieldQoS.AutomaticReadout));
1410 }
1411
1412 if (e.HasFeature(XmppClient.NamespaceSoftwareVersion))
1413 {
1414 this.client.SendSoftwareVersionRequest(string.Empty, (sender2, e2) =>
1415 {
1416 Now = DateTime.Now;
1417
1418 if (e2.Ok)
1419 {
1420 Request.LogFields(new Waher.Things.SensorData.Field[]
1421 {
1422 new StringField(Waher.Things.ThingReference.Empty, Now, "Server, Name", e2.Name,
1423 FieldType.Identity, FieldQoS.AutomaticReadout),
1424 new StringField(Waher.Things.ThingReference.Empty, Now, "Server, OS", e2.OS,
1425 FieldType.Identity, FieldQoS.AutomaticReadout),
1426 new StringField(Waher.Things.ThingReference.Empty, Now, "Server, Version", e2.Version,
1427 FieldType.Identity, FieldQoS.AutomaticReadout),
1428 });
1429 }
1430 else
1431 {
1432 Request.LogErrors(new Waher.Things.ThingError[]
1433 {
1434 new Waher.Things.ThingError(Waher.Things.ThingReference.Empty, Now, "Unable to read software version.")
1435 });
1436 }
1437
1438 VersionDone = true;
1439
1440 if (VersionDone)
1441 Request.Done();
1442
1443 return Task.CompletedTask;
1444
1445 }, null);
1446 }
1447 else
1448 VersionDone = true;
1449 }
1450 else
1451 VersionDone = true;
1452
1453 Request.LogFields(Fields);
1454
1455 if (VersionDone)
1456 Request.Done();
1457 }
1458 else
1459 Request.Fail("Unable to perform a service discovery.");
1460
1461 return Task.CompletedTask;
1462
1463 }, null);
1464
1465 return Request;
1466 }
1467
1468 public void RegisterComponent(XmppComponent Component)
1469 {
1470 lock (this.components)
1471 {
1472 if (!this.components.Contains(Component))
1473 this.components.AddLast(Component);
1474 }
1475 }
1476
1477 public bool UnregisterComponent(XmppComponent Component)
1478 {
1479 lock (this.components)
1480 {
1481 return this.components.Remove(Component);
1482 }
1483 }
1484
1485 public void AddContexMenuItems(TreeNode Node, ref string CurrentGroup, ContextMenu Menu)
1486 {
1487 LinkedList<IMenuAggregator> Aggregators = null;
1488 MenuItem Item;
1489
1490 if (Node == this)
1491 {
1492 this.GroupSeparator(ref CurrentGroup, "Connection", Menu);
1493
1494 Menu.Items.Add(Item = new MenuItem()
1495 {
1496 Header = "_Change password...",
1497 IsEnabled = (!(this.client is null) && this.client.State == XmppState.Connected)
1498 });
1499
1500 Item.Click += this.ChangePassword_Click;
1501 }
1502
1503 lock (this.components)
1504 {
1505 foreach (XmppComponent Component in this.components)
1506 {
1507 if (Component is IMenuAggregator MenuAggregator)
1508 {
1509 if (Aggregators is null)
1510 Aggregators = new LinkedList<IMenuAggregator>();
1511
1512 Aggregators.AddLast(MenuAggregator);
1513 }
1514 }
1515 }
1516
1517 if (!(Aggregators is null))
1518 {
1519 foreach (IMenuAggregator Aggregator in Aggregators)
1520 Aggregator.AddContexMenuItems(Node, ref CurrentGroup, Menu);
1521 }
1522 }
1523
1524 private void ChangePassword_Click(object Sender, RoutedEventArgs e)
1525 {
1527 bool? Result = Dialog.ShowDialog();
1528
1529 if (Result.HasValue && Result.Value)
1530 {
1531 this.client.ChangePassword(Dialog.Password.Password, (sender2, e2) =>
1532 {
1533 if (e2.Ok)
1534 {
1535 this.connections.Modified = true;
1536 this.password = Dialog.Password.Password;
1537 this.passwordHash = string.Empty;
1538 this.passwordHashMethod = string.Empty;
1539 this.client.Reconnect(this.client.UserName, this.password);
1540
1541 MainWindow.SuccessBox("Password successfully changed.");
1542 }
1543 else
1544 MainWindow.ErrorBox("Unable to change password.");
1545
1546 return Task.CompletedTask;
1547
1548 }, null);
1549 }
1550 }
1551
1552 public override void Edit()
1553 {
1554 ConnectToForm Dialog = new ConnectToForm()
1555 {
1556 Owner = MainWindow.currentInstance
1557 };
1558
1559 Dialog.XmppServer.Text = this.host;
1560 Dialog.XmppPort.Text = this.port.ToString();
1561 Dialog.UrlEndpoint.Text = this.urlBindResource;
1562 Dialog.ConnectionMethod.SelectedIndex = (int)this.transport;
1563 Dialog.AccountName.Text = this.account;
1564 Dialog.Password.Password = this.passwordHash;
1565 Dialog.RetypePassword.Password = this.passwordHash;
1566 Dialog.PasswordHash = this.passwordHash;
1567 Dialog.PasswordHashMethod = this.passwordHashMethod;
1568 Dialog.TrustServerCertificate.IsChecked = this.trustCertificate;
1569 Dialog.AllowInsecureAuthentication.IsChecked = this.allowInsecureAuthentication;
1570
1571 bool? Result = Dialog.ShowDialog();
1572
1573 if (Result.HasValue && Result.Value)
1574 {
1575 this.transport = (TransportMethod)Dialog.ConnectionMethod.SelectedIndex;
1576 this.host = Dialog.XmppServer.Text;
1577 this.urlBindResource = Dialog.UrlEndpoint.Text;
1578 this.account = Dialog.AccountName.Text;
1579 this.passwordHash = Dialog.PasswordHash;
1580 this.passwordHashMethod = Dialog.PasswordHashMethod;
1581 this.trustCertificate = Dialog.TrustServerCertificate.IsChecked.HasValue && Dialog.TrustServerCertificate.IsChecked.Value;
1582 this.allowInsecureAuthentication = Dialog.AllowInsecureAuthentication.IsChecked.HasValue && Dialog.AllowInsecureAuthentication.IsChecked.Value;
1583
1584 if (!int.TryParse(Dialog.XmppPort.Text, out this.port))
1585 this.port = XmppCredentials.DefaultPort;
1586
1587 this.OnUpdated();
1588 }
1589 }
1590
1591 private Task PepClient_SensorData(object _, PersonalEventNotificationEventArgs e)
1592 {
1594 !(SensorData.Fields is null) &&
1595 this.TryGetChild(e.FromBareJID, out TreeNode Node))
1596 {
1598
1600 {
1601 if (F is Int32Field I32)
1602 Parameters.Add(new Int32Parameter(F.Name, F.Name, I32.Value));
1603 else if (F is Int64Field I64)
1604 Parameters.Add(new Int64Parameter(F.Name, F.Name, I64.Value));
1605 else
1607 StringParameter(F.Name, F.Name, F.ValueString));
1608 }
1609
1610 Node.Add(Parameters.ToArray());
1611 Node.OnUpdated();
1612 }
1613
1614 return Task.CompletedTask;
1615 }
1616
1617 private Task PepClient_OnUserTune(object _, UserTuneEventArgs e)
1618 {
1619 if (this.TryGetChild(e.FromBareJID, out TreeNode Node))
1620 {
1621 Node.Add(
1622 new Waher.Things.DisplayableParameters.StringParameter("Tune_Artist", "Artist", e.Tune.Artist),
1623 new Waher.Things.DisplayableParameters.StringParameter("Tune_Length", "Length", e.Tune.Length?.ToString() ?? string.Empty),
1624 new Waher.Things.DisplayableParameters.StringParameter("Tune_Rating", "Rating", e.Tune.Rating?.ToString() ?? string.Empty),
1625 new Waher.Things.DisplayableParameters.StringParameter("Tune_Source", "Source", e.Tune.Source),
1626 new Waher.Things.DisplayableParameters.StringParameter("Tune_Title", "Title", e.Tune.Title),
1627 new Waher.Things.DisplayableParameters.StringParameter("Tune_Track", "Track", e.Tune.Track),
1628 new Waher.Things.DisplayableParameters.StringParameter("Tune_URI", "URI", e.Tune.Uri?.ToString() ?? string.Empty));
1629
1630 Node.OnUpdated();
1631 }
1632
1633 return Task.CompletedTask;
1634 }
1635
1636 private Task PepClient_OnUserMood(object _, UserMoodEventArgs e)
1637 {
1638 if (this.TryGetChild(e.FromBareJID, out TreeNode Node))
1639 {
1640 Node.Add(
1641 new Waher.Things.DisplayableParameters.StringParameter("Mood_Mood", "Mood", e.Mood.Mood?.ToString() ?? string.Empty),
1642 new Waher.Things.DisplayableParameters.StringParameter("Mood_Text", "Text", e.Mood.Text));
1643
1644 Node.OnUpdated();
1645 }
1646
1647 return Task.CompletedTask;
1648 }
1649
1650 private Task PepClient_OnUserLocation(object _, UserLocationEventArgs e)
1651 {
1652 if (this.TryGetChild(e.FromBareJID, out TreeNode Node))
1653 {
1654 Node.Add(
1655 new Waher.Things.DisplayableParameters.StringParameter("Location_Artist", "Accuracy", e.Location.Accuracy?.ToString() ?? string.Empty),
1656 new Waher.Things.DisplayableParameters.StringParameter("Location_Alt", "Alt", e.Location.Alt?.ToString() ?? string.Empty),
1657 new Waher.Things.DisplayableParameters.StringParameter("Location_AltAccuracy", "AltAccuracy", e.Location.AltAccuracy?.ToString() ?? string.Empty),
1658 new Waher.Things.DisplayableParameters.StringParameter("Location_Area", "Area", e.Location.Area ?? string.Empty),
1659 new Waher.Things.DisplayableParameters.StringParameter("Location_Bearing", "Bearing", e.Location.Bearing?.ToString() ?? string.Empty),
1660 new Waher.Things.DisplayableParameters.StringParameter("Location_Building", "Building", e.Location.Building ?? string.Empty),
1661 new Waher.Things.DisplayableParameters.StringParameter("Location_Country", "Country", e.Location.Country ?? string.Empty),
1662 new Waher.Things.DisplayableParameters.StringParameter("Location_CountryCode", "CountryCode", e.Location.CountryCode ?? string.Empty),
1663 new Waher.Things.DisplayableParameters.StringParameter("Location_Datum", "Datum", e.Location.Datum ?? string.Empty),
1664 new Waher.Things.DisplayableParameters.StringParameter("Location_Description", "Description", e.Location.Description ?? string.Empty),
1665 new Waher.Things.DisplayableParameters.StringParameter("Location_Floor", "Floor", e.Location.Floor ?? string.Empty),
1666 new Waher.Things.DisplayableParameters.StringParameter("Location_Lat", "Lat", e.Location.Lat?.ToString() ?? string.Empty),
1667 new Waher.Things.DisplayableParameters.StringParameter("Location_Lon", "Lon", e.Location.Lon?.ToString() ?? string.Empty),
1668 new Waher.Things.DisplayableParameters.StringParameter("Location_Locality", "Locality", e.Location.Locality ?? string.Empty),
1669 new Waher.Things.DisplayableParameters.StringParameter("Location_PostalCode", "PostalCode", e.Location.PostalCode ?? string.Empty),
1670 new Waher.Things.DisplayableParameters.StringParameter("Location_Region", "Region", e.Location.Region ?? string.Empty),
1671 new Waher.Things.DisplayableParameters.StringParameter("Location_Room", "Room", e.Location.Room ?? string.Empty),
1672 new Waher.Things.DisplayableParameters.StringParameter("Location_Speed", "Speed", e.Location.Speed?.ToString() ?? string.Empty),
1673 new Waher.Things.DisplayableParameters.StringParameter("Location_Street", "Street", e.Location.Street ?? string.Empty),
1674 new Waher.Things.DisplayableParameters.StringParameter("Location_Text", "Text", e.Location.Text ?? string.Empty),
1675 new Waher.Things.DisplayableParameters.StringParameter("Location_Timestamp", "Timestamp", e.Location.Timestamp?.ToString() ?? string.Empty),
1676 new Waher.Things.DisplayableParameters.StringParameter("Location_TimeZone", "TimeZone", e.Location.TimeZone ?? string.Empty),
1677 new Waher.Things.DisplayableParameters.StringParameter("Location_URI", "URI", e.Location.Uri?.ToString() ?? string.Empty));
1678
1679 Node.OnUpdated();
1680 }
1681
1682 return Task.CompletedTask;
1683 }
1684
1685 private Task PepClient_OnUserActivity(object _, UserActivityEventArgs e)
1686 {
1687 if (this.TryGetChild(e.FromBareJID, out TreeNode Node))
1688 {
1689 Node.Add(
1690 new Waher.Things.DisplayableParameters.StringParameter("Activity_General", "General", e.Activity.GeneralActivity?.ToString() ?? string.Empty),
1691 new Waher.Things.DisplayableParameters.StringParameter("Activity_Specific", "Specific", e.Activity.SpecificActivity?.ToString() ?? string.Empty),
1692 new Waher.Things.DisplayableParameters.StringParameter("Activity_Text", "Text", e.Activity.Text));
1693
1694 Node.OnUpdated();
1695 }
1696
1697 return Task.CompletedTask;
1698 }
1699
1700 private Task PepClient_OnUserAvatarMetaData(object _, UserAvatarMetaDataEventArgs e)
1701 {
1702 // TODO: Avatars
1703 return Task.CompletedTask;
1704 }
1705
1706 private void ServerlessMessaging_OnNewXmppClient(object _, PeerConnectionEventArgs e)
1707 {
1708 XmppClient Client = e.Client;
1709
1710 this.e2eEncryption.RegisterHandlers(Client);
1711 }
1712
1713 private void ServerlessMessaging_OnResynch(object _, ResynchEventArgs e)
1714 {
1715 if (this.e2eEncryption is null)
1716 e.Done(false);
1717 else
1718 {
1719 this.e2eEncryption.SynchronizeE2e(e.RemoteFullJid, (Sender2, e2) =>
1720 {
1721 return e.Done(e2.Ok);
1722 });
1723 }
1724 }
1725
1726 internal void ReregisterView(string SessionId, RemoteDesktopView View)
1727 {
1728 lock (this.activeViews)
1729 {
1730 this.activeViews[SessionId] = View;
1731 }
1732 }
1733
1734 internal void UnregisterView(RemoteDesktopView View)
1735 {
1736 lock (this.activeViews)
1737 {
1738 this.activeViews.Remove(View.Session.SessionId);
1739 }
1740 }
1741
1742 private Task Proxy_OnOpen(object _, ValidateStreamEventArgs e)
1743 {
1744 RemoteDesktopView View;
1745
1746 lock (this.activeViews)
1747 {
1748 if (!this.activeViews.TryGetValue(e.StreamId, out View))
1749 return Task.CompletedTask;
1750 }
1751
1752 e.AcceptStream(View.Socks5DataReceived, View.Socks5StreamClosed, null);
1753
1754 return Task.CompletedTask;
1755 }
1756
1760 public override bool CanCopy => !(this.client is null);
1761
1765 public override void Copy()
1766 {
1767 Clipboard.SetText("xmpp:" + this.client.BareJID);
1768 }
1769
1773 public override bool CanPaste
1774 {
1775 get
1776 {
1777 return this.CanPasteFromClipboard(out _);
1778 }
1779 }
1780
1781 private bool CanPasteFromClipboard(out string BareJid)
1782 {
1783 BareJid = null;
1784
1785 if (this.client is null || this.client.State != XmppState.Connected)
1786 return false;
1787
1788 if (!Clipboard.ContainsText(TextDataFormat.Text))
1789 return false;
1790
1791 string s = Clipboard.GetText(TextDataFormat.Text);
1792 if (!s.StartsWith("xmpp:"))
1793 return false;
1794
1795 s = s.Substring(5);
1796 if (!XmppClient.BareJidRegEx.IsMatch(s))
1797 return false;
1798
1799 BareJid = s;
1800 return true;
1801 }
1802
1806 public override void Paste()
1807 {
1808 if (this.CanPasteFromClipboard(out string BareJid))
1809 this.client.RequestPresenceSubscription(BareJid);
1810 }
1811 }
1812}
Interaction logic for App.xaml
Definition: App.xaml.cs:9
Interaction logic for ConnectionView.xaml
Interaction logic for LogView.xaml
Definition: LogView.xaml.cs:23
Represents one item in an event log output.
Definition: LogItem.cs:14
Interaction logic for RemoteDesktopView.xaml
Interaction logic for SnifferView.xaml
Interaction logic for AddContactForm.xaml
Interaction logic for ChangePasswordForm.xaml
Interaction logic for ConnectToForm.xaml
string PasswordHash
Password hash of a successfully authenticated client.
string PasswordHashMethod
Password hash method of a successfully authenticated client.
Interaction logic for xaml
Represents a node in a concentrator.
Definition: Node.cs:33
override void Add()
Is called when the user wants to add a node to the current node.
Definition: Node.cs:422
override string Key
Key in parent child collection.
Definition: Node.cs:79
override bool CanRecycle
If the node can be recycled.
Definition: Node.cs:94
Maintains the set of open connections.
Definition: Connections.cs:15
Represents a simple XMPP actuator.
Definition: XmppActuator.cs:18
Represents a simple XMPP sensor.
Definition: XmppSensor.cs:14
Abstract base class for tree nodes in the connection view.
Definition: TreeNode.cs:24
object Tag
Object tagged to the node.
Definition: TreeNode.cs:113
TreeNode Parent
Parent node. May be null if a root node.
Definition: TreeNode.cs:107
bool TryGetChild(string ChildKey, out TreeNode Child)
Tries to get the child node corresponding to a given key.
Definition: TreeNode.cs:96
virtual Task Recycle(MainWindow Window)
Is called when the user wants to recycle the node.
Definition: TreeNode.cs:442
virtual void OnUpdated()
Raises the Updated event.
Definition: TreeNode.cs:224
EventHandler Updated
Raised when the node has been updated. The sender argument will contain a reference to the node.
Definition: TreeNode.cs:219
Class representing a normal XMPP account.
override Task< bool > RemoveSniffer(ISniffer Sniffer)
Removes a sniffer from the node.
override async Task GetConfigurationForm(EventHandlerAsync< DataFormEventArgs > Callback, object State)
Gets the configuration form for the node.
override async Task Recycle(MainWindow Window)
Is called when the user wants to recycle the node.
override Task< SensorDataClientRequest > StartSensorDataFullReadout()
Starts readout of all sensor data values.
override void Added(MainWindow Window)
Is called when the node has been added to the main window.
XmppAccountNode(Connections Connections, TreeNode Parent, string Host, TransportMethod Transport, int Port, string UrlBindResource, string Account, string PasswordHash, string PasswordHashMethod, bool TrustCertificate, bool AllowInsecureAuthentication)
Class representing a normal XMPP account.
void AddContexMenuItems(TreeNode Node, ref string CurrentGroup, ContextMenu Menu)
Adds context menu items for a node.
override void Write(XmlWriter Output)
Saves the object to a file.
override void Edit()
Is called when the user wants to edit a node.
override Task< SensorDataClientRequest > StartSensorDataMomentaryReadout()
Starts readout of momentary sensor data values.
override void Dispose()
Disposes of the node and its resources.
override void Removed(MainWindow Window)
Is called when the node has been removed from the main window.
override void Add()
Is called when the user wants to add a node to the current node.
override void Copy()
Is called when the user wants to copy the node to the clipboard.
override bool RemoveChild(TreeNode Node)
Removes a child node.
override void Paste()
Is called when the user wants to paste data from the clipboard to the node.
Represents an XMPP contact whose capabilities have not been measured.
Definition: XmppContact.cs:24
Represents an unspecialized XMPP contact.
Definition: XmppOther.cs:14
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Definition: CommonTypes.cs:594
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
Event arguments for XmppEventReceptor.OnEvent events.
This class handles incoming events from the XMPP network. The default behaviour is to log incoming ev...
void Dispose()
IDisposable.Dispose
virtual bool Remove(ISniffer Sniffer)
ICommunicationLayer.Remove
virtual void AddRange(IEnumerable< ISniffer > Sniffers)
ICommunicationLayer.AddRange
Task Information(string Comment)
Called to inform the viewer of something.
Task Warning(string Warning)
Called to inform the viewer of a warning state.
virtual void Add(ISniffer Sniffer)
ICommunicationLayer.Add
Implements an XMPP concentrator client interface.
override void Dispose()
Disposes of the extension.
Implements an XMPP concentrator server interface.
static readonly string[] NamespacesConcentrator
Supported concentrator namespaces.
Static class managing editable parameters in objects. Editable parameters are defined by using the at...
Definition: Parameters.cs:25
String-valued contractual parameter
Implements an XMPP control client interface.
static readonly string[] NamespacesControl
Supported control namespaces
Event arguments for data form results.
Implements support for data forms. Data Forms are defined in the following XEPs:
Definition: DataForm.cs:42
Abstract base class for all data types used in forms.
Definition: DataType.cs:7
Base class for form fields
Definition: Field.cs:16
DataForm Form
Data Form containing the field.
Definition: Field.cs:73
override void Validate(Field Field, DataType DataType, object[] Parsed, string[] Strings)
Validates the contents of a field. If an error is found, the Field.Error property is set accordingly....
Event arguments for responses to IQ queries.
bool Ok
If the response is an OK result response (true), or an error response (false).
object State
State object passed to the original request.
Event arguments for message events.
string FromBareJID
Bare JID of resource sending the message.
string ErrorText
Any error specific text.
Event arguments for presence events.
bool Ok
If the response is an OK result response (true), or an error response (false).
string From
From where the presence was received.
string FromBareJID
Bare JID of resource sending the presence.
Availability Availability
Resource availability.
async Task Decline()
Declines a subscription or unsubscription request.
async Task Accept()
Accepts a subscription or unsubscription request.
XmppClient Client
XMPP Client. Is null if event raised by a component.
Client managing communication with a Multi-User-Chat service. https://xmpp.org/extensions/xep-0045....
override void Dispose()
Disposes of the extension.
Class managing end-to-end encryption.
virtual void RegisterHandlers(XmppClient Client)
Registers XMPP stanza handlers
Task SynchronizeE2e(string FullJID, EventHandlerAsync< IqResultEventArgs > Callback)
Synchronizes End-to-End Encryption and Peer-to-Peer connectivity parameters with a remote entity.
virtual void Dispose()
IDisposable.Dispose
XmppClient Client
XMPP client, if aquired, or null otherwise.
Peer connection event arguments.
Task Done(bool Ok)
Method called by callback, to report that the synchronization succeeded (Ok =true),...
string RemoteFullJid
JID of the remote end-point.
Class managing a SOCKS5 proxy associated with the current XMPP server.
Definition: Socks5Proxy.cs:19
bool AcceptStream(EventHandlerAsync< DataReceivedEventArgs > DataCallback, EventHandlerAsync< StreamEventArgs > CloseCallback, object State)
Call this method to accept the incoming stream.
IPersonalEvent PersonalEvent
Parsed personal event, if appropriate type was found.
Event arguments for user mood events.
Event arguments for user tune events.
Client managing the Personal Eventing Protocol (XEP-0163). https://xmpp.org/extensions/xep-0163....
Definition: PepClient.cs:19
void RegisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Registers an event handler of a specific type of personal events.
Definition: PepClient.cs:345
override void Dispose()
Disposes of the extension.
Definition: PepClient.cs:55
UserGeneralActivities? GeneralActivity
User general activity
string Text
Custom text provided by the use.
UserSpecificActivities? SpecificActivity
User specific activity
string Building
A specific building on a street or in an area
string Region
An administrative region of the nation, such as a state or province
Uri Uri
A URI or URL pointing to information about the location
string Floor
A particular floor in a building
string Street
A thoroughfare within the locality, or a crossing of two thoroughfares
decimal? Lon
Longitude in decimal degrees East
decimal? Bearing
GPS bearing (direction in which the entity is heading to reach its next waypoint),...
string Country
The nation where the user is located
decimal? AltAccuracy
Vertical GPS error in meters
string TimeZone
The time zone offset from UTC for the current location
decimal? Lat
Latitude in decimal degrees North
string CountryCode
The ISO 3166 two-letter country code
decimal? Alt
Altitude in meters above or below sea level
decimal? Speed
The speed at which the entity is moving, in meters per second
string PostalCode
A code used for postal delivery
string Text
A catch-all element that captures any other information about the location
decimal? Accuracy
Horizontal GPS error in meters.
string Area
A named area such as a campus or neighborhood
string Room
A particular room in a building
DateTime? Timestamp
UTC timestamp specifying the moment when the reading was taken.
string Locality
A locality within the administrative region, such as a town or city
string Description
A natural-language name for or description of the location
UserMoods? Mood
User mood
Definition: UserMood.cs:531
string Text
Custom text provided by the use.
Definition: UserMood.cs:540
string Title
The title of the song or piece
Definition: UserTune.cs:149
byte? Rating
The user's rating of the song or piece, from 1 (lowest) to 10 (highest).
Definition: UserTune.cs:185
Uri Uri
A URI or URL pointing to information about the song, collection, or artist
Definition: UserTune.cs:167
string Track
A unique identifier for the tune; e.g., the track number within a collection or the specific URI for ...
Definition: UserTune.cs:158
string Source
The collection (e.g., album) or other source (e.g., a band website that hosts streams or audio files)
Definition: UserTune.cs:140
ushort? Length
The duration of the song or piece in seconds
Definition: UserTune.cs:176
string Artist
The artist or performer of the song or piece
Definition: UserTune.cs:131
override void Dispose()
Disposes of the extension.
const string RemoteDesktopNamespace
http://waher.se/rdp/1.0
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
string[] Groups
Any groups the roster item belongs to.
Definition: RosterItem.cs:186
string Name
Name of the roster item.
Definition: RosterItem.cs:282
new Task LogFields(IEnumerable< Field > Fields)
Fields logged.
Implements an XMPP sensor client interface.
Definition: SensorClient.cs:21
static readonly string[] NamespacesSensorEvents
Supported sensor event namespaces.
Definition: SensorClient.cs:64
override void Dispose()
Disposes of the extension.
static readonly string[] NamespacesSensorData
Supported sensor-data namespaces.
Definition: SensorClient.cs:40
Contains personal sensor data.
Definition: SensorData.cs:15
IEnumerable< Field > Fields
Sensor data fields.
Definition: SensorData.cs:73
Contains information about an item of an entity.
Definition: Item.cs:11
bool HasFeature(string Feature)
Checks if the remote entity supports a specific feature.
bool HasAnyFeature(params string[] Features)
Checks if the remote entity supports any of a set of features.
Implements the clock synchronization extesion as defined by the Neuro-Foundation (neuro-foundation....
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
Task ChangePassword(string NewPassword)
Changes the password of the current user.
Definition: XmppClient.cs:4256
XmppState State
Current state of connection.
Definition: XmppClient.cs:985
Task OfflineAndDisposeAsync()
Sends an offline presence, and then disposes the object by calling DisposeAsync.
Definition: XmppClient.cs:1119
Task RemoveRosterItem(string BareJID)
Removes an item from the roster.
Definition: XmppClient.cs:4631
const string NamespaceSoftwareVersion
jabber:iq:version
Definition: XmppClient.cs:128
Task UpdateRosterItem(string BareJID, string Name, params string[] Groups)
Updates an item in the roster.
Definition: XmppClient.cs:4586
Task RequestPresenceSubscription(string BareJid)
Requests subscription of presence information from a contact.
Definition: XmppClient.cs:4919
string PasswordHashMethod
Password hash method.
Definition: XmppClient.cs:3445
static readonly Regex BareJidRegEx
Regular expression for Bare JIDs
Definition: XmppClient.cs:188
async Task Reconnect()
Reconnects a client after an error or if it's offline. Reconnecting, instead of creating a completely...
Definition: XmppClient.cs:1269
Task RequestPresenceUnsubscription(string BareJid)
Requests unssubscription of presence information from a contact.
Definition: XmppClient.cs:4980
bool RemoveTag(string TagName)
Removes a tag from the client.
Definition: XmppClient.cs:7223
void SetTag(string TagName, object Tag)
Sets a tag value.
Definition: XmppClient.cs:7249
Task SendServiceDiscoveryRequest(string To, EventHandlerAsync< ServiceDiscoveryEventArgs > Callback, object State)
Sends a service discovery request
Definition: XmppClient.cs:5806
string PasswordHash
Hash value of password. Depends on method used to authenticate user.
Definition: XmppClient.cs:3436
Task Connect()
Connects the client.
Definition: XmppClient.cs:641
string Domain
Current Domain.
Definition: XmppClient.cs:3453
Task SendServiceItemsDiscoveryRequest(string To, EventHandlerAsync< ServiceItemsDiscoveryEventArgs > Callback, object State)
Sends a service items discovery request
Definition: XmppClient.cs:6061
Task SetPresence()
Sets the presence of the connection. Add a CustomPresenceXml event handler to add custom presence XML...
Definition: XmppClient.cs:4776
RosterItem[] Roster
Items in the roster.
Definition: XmppClient.cs:4671
RosterItem GetRosterItem(string BareJID)
Gets a roster item.
Definition: XmppClient.cs:4522
Manages an XMPP component connection, as defined in XEP-0114: http://xmpp.org/extensions/xep-0114....
Class containing credentials for an XMPP client connection.
const int DefaultPort
Default XMPP Server port.
virtual void Dispose()
Disposes of the extension.
Base class for all node parameters.
Definition: Parameter.cs:10
Base class for all sensor data fields.
Definition: Field.cs:20
Represents a 32-bit integer value.
Definition: Int32Field.cs:10
Represents a 64-bit integer value.
Definition: Int64Field.cs:10
Interface for nodes that can aggregate items in menues to descendant nodes.
void AddContexMenuItems(TreeNode Node, ref string CurrentGroup, ContextMenu Menu)
Adds context menu items for a node.
Interface for objects that contain a reference to a host.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Definition: ISniffer.cs:11
Availability
Resource availability.
Definition: Availability.cs:7
SubscriptionState
State of a presence subscription.
Definition: RosterItem.cs:16
XmppState
State of XMPP connection.
Definition: XmppState.cs:7
PendingSubscription
Pending subscription states.
Definition: RosterItem.cs:54
FieldType
Field Type flags
Definition: FieldType.cs:10
Definition: App.xaml.cs:4