2using System.Collections.Generic;
3using System.Threading.Tasks;
5using System.Windows.Controls;
6using System.Windows.Media;
7using System.Windows.Media.Imaging;
50 public enum TransportMethod
52 TraditionalSocket = 0,
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";
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);
86 private DateTime connectionTimer = DateTime.MinValue;
87 private Exception lastError =
null;
88 private TransportMethod transport = TransportMethod.TraditionalSocket;
90 private string domain;
91 private string urlBindResource;
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;
118 string Account,
string PasswordHash,
string PasswordHashMethod,
bool TrustCertificate,
bool AllowInsecureAuthentication)
122 this.host = this.domain =
Host;
123 this.transport = Transport;
125 this.urlBindResource = UrlBindResource;
126 this.account = Account;
128 if (
string.IsNullOrEmpty(PasswordHashMethod))
130 this.password = PasswordHash;
131 this.passwordHash =
string.Empty;
132 this.passwordHashMethod =
string.Empty;
133 this.supportsHashes =
false;
137 this.password =
string.Empty;
138 this.passwordHash = PasswordHash;
139 this.passwordHashMethod = PasswordHashMethod;
140 this.supportsHashes =
true;
143 this.trustCertificate = TrustCertificate;
144 this.allowInsecureAuthentication = AllowInsecureAuthentication;
154 this.transport =
XML.
Attribute(E,
"transport", TransportMethod.TraditionalSocket);
155 this.urlBindResource =
XML.
Attribute(E,
"urlBindResource");
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);
169 private void Init(params
ISniffer[] Sniffers)
175 Account = this.account,
176 TrustServer = this.trustCertificate,
177 AllowPlain = this.allowInsecureAuthentication,
178 AllowCramMD5 = this.allowInsecureAuthentication,
179 AllowDigestMD5 = this.allowInsecureAuthentication
182 switch (this.transport)
184 case TransportMethod.BOSH:
185 case TransportMethod.WS:
186 Credentials.UriEndpoint = this.urlBindResource;
190 if (!
string.IsNullOrEmpty(this.passwordHash))
192 Credentials.Password = this.passwordHash;
193 Credentials.PasswordType = this.passwordHashMethod;
196 Credentials.Password = this.password;
198 this.client =
new XmppClient(Credentials,
"en", typeof(
App).Assembly)
200 AllowQuickLogin =
true,
203 if (!(Sniffers is
null))
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;
226 this.eventReceptor.OnEvent += this.EventReceptor_OnEvent;
228 this.AddPepClient(
string.Empty);
230 this.concentratorClient.OnCustomSnifferMessage += this.ConcentratorClient_OnCustomSnifferMessage;
231 this.concentratorClient.OnEvent += this.ConcentratorClient_OnEvent;
239 this.client.
SetTag(
"E2E", this.e2eEncryption);
242 this.socks5Proxy.OnOpen += this.Proxy_OnOpen;
252 if (!
string.IsNullOrEmpty(Msg))
255 return Task.CompletedTask;
258 private void AddPepClient(
string PubSubComponentAddress)
261 this.pepClient =
null;
263 this.pepClient =
new PepClient(this.client, PubSubComponentAddress);
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;
273 private void AddMucClient(
string MucComponentAddress)
276 this.mucClient =
null;
287 return Task.CompletedTask;
290 return Task.CompletedTask;
295 TaskCompletionSource<SnifferView> View =
new TaskCompletionSource<SnifferView>();
300 return Task.CompletedTask;
313 await Concentrator.ConcentratorClient_OnEvent(Sender, EventMessage);
319 DateTime Now = DateTime.Now;
320 DateTime Limit = Now.AddMinutes(-1);
322 lock (this.unhandledMessages)
324 this.unhandledMessages.AddLast(
new KeyValuePair<DateTime, MessageEventArgs>(Now, e));
326 while (!(this.unhandledMessages.First is
null) &&
this.unhandledMessages.First.Value.Key <= Limit)
327 this.unhandledMessages.RemoveFirst();
330 return Task.CompletedTask;
333 public IEnumerable<MessageEventArgs> GetUnhandledMessages(
string LocalName,
string Namespace)
335 LinkedList<MessageEventArgs> Result =
new LinkedList<MessageEventArgs>();
336 LinkedListNode<KeyValuePair<DateTime, MessageEventArgs>> Loop, Next;
339 lock (this.unhandledMessages)
341 Loop = this.unhandledMessages.First;
343 while (!(Loop is
null))
349 foreach (XmlElement E
in Loop.Value.Value.Message.ChildNodes)
351 if (E.LocalName == LocalName && E.NamespaceURI == Namespace)
360 Result.AddLast(Loop.Value.Value);
361 this.unhandledMessages.Remove(Loop);
371 private Task Client_OnError(
object _, Exception Exception)
373 this.lastError = Exception;
374 return Task.CompletedTask;
377 private async Task Client_OnStateChanged(
object _,
XmppState NewState)
382 this.connected =
true;
383 this.lastError =
null;
385 if (this.supportsHashes &&
string.IsNullOrEmpty(this.passwordHash))
389 this.connections.Modified =
true;
392 if (this.domain != this.client.
Domain)
394 this.domain = this.client.
Domain;
395 this.connections.Modified =
true;
399 this.SearchComponents();
405 bool ImmediateReconnect = this.connected;
406 this.connected =
false;
408 if (ImmediateReconnect && !(this.client is
null))
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;
426 public override string Header
428 get {
return this.account +
"@" + this.domain; }
431 public override string TypeName
433 get {
return "XMPP Account"; }
440 if (this.connectionTimer > DateTime.MinValue)
442 MainWindow.Scheduler?.Remove(this.connectionTimer);
443 this.connectionTimer = DateTime.MinValue;
447 this.rdpClient =
null;
450 this.pepClient =
null;
453 this.mucClient =
null;
456 this.sensorClient =
null;
459 this.controlClient =
null;
461 this.concentratorClient?.
Dispose();
462 this.concentratorClient =
null;
464 this.synchronizationClient?.
Dispose();
465 this.synchronizationClient =
null;
468 this.e2eEncryption =
null;
471 this.eventReceptor =
null;
473 if (!(this.client is
null))
483 private async
void CheckConnection(
object P)
487 this.connectionTimer =
MainWindow.Scheduler.Add(DateTime.Now.AddMinutes(1),
this.CheckConnection,
null);
489 if (!(this.client is
null) && (this.client.
State ==
XmppState.Offline ||
this.client.State ==
XmppState.Error ||
this.client.State ==
XmppState.Authenticating))
494 MessageBox.Show(
MainWindow.currentInstance, ex.Message,
"Unable to reconnect.", MessageBoxButton.OK, MessageBoxImage.Error);
498 public override void Write(XmlWriter Output)
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);
507 Output.WriteAttributeString(
"account", this.account);
509 if (
string.IsNullOrEmpty(this.passwordHash))
510 Output.WriteAttributeString(
"password", this.password);
513 Output.WriteAttributeString(
"passwordHash", this.passwordHash);
514 Output.WriteAttributeString(
"passwordHashMethod", this.passwordHashMethod);
517 Output.WriteAttributeString(
"trustCertificate",
CommonTypes.
Encode(
this.trustCertificate));
518 Output.WriteAttributeString(
"allowInsecureAuthentication",
CommonTypes.
Encode(
this.allowInsecureAuthentication));
520 if (!this.supportsHashes)
521 Output.WriteAttributeString(
"supportsHashes",
CommonTypes.
Encode(
this.supportsHashes));
523 Output.WriteEndElement();
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));
548 public override ImageSource ImageResource
552 if (this.client is
null)
556 switch (this.client.
State)
572 public override string ToolTip
576 switch (this.client.
State)
583 return "Connecting to broker.";
586 return "Performing Stream Negotiation.";
589 return "Stream Opened.";
592 return "Switching to encrypted channel.";
595 return "Performing user authentication.";
598 return "Registering user account.";
601 return "Performing session binding.";
604 return "Fetching roster.";
607 return "Setting presence.";
613 if (this.lastError is
null)
614 return "In an error state.";
616 return this.lastError.Message;
621 public override bool CanAddChildren
625 return !(this.client is
null) && this.client.
State ==
XmppState.Connected;
629 public override bool CanEdit =>
true;
630 public override bool CanDelete =>
true;
632 public override void Add()
636 Owner = this.connections.Owner
639 bool? Result = Dialog.ShowDialog();
641 if (Result.HasValue && Result.Value)
645 private void CheckRoster()
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;
654 if (Contacts is
null)
655 Contacts =
new SortedDictionary<string, TreeNode>();
661 if (Contacts.TryGetValue(
Item.BareJid, out
TreeNode Contact))
662 Existing[
Item.BareJid] = Contact;
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));
674 Contact =
new XmppContact(
this, this.client,
Item.BareJid,
Item.IsInGroup(RemoteDesktopGroupName));
676 Contacts[
Item.BareJid] = Contact;
679 Added =
new LinkedList<TreeNode>();
681 Added.AddLast(Contact);
684 switch (
Item.PendingSubscription)
687 if (Resubscribe is
null)
688 Resubscribe =
new LinkedList<RosterItem>();
690 Resubscribe.AddLast(
Item);
694 if (Reunsubscribe is
null)
695 Reunsubscribe =
new LinkedList<RosterItem>();
697 Reunsubscribe.AddLast(
Item);
702 if (this.children is
null)
703 this.children = Contacts;
706 foreach (KeyValuePair<string, TreeNode> P
in this.children)
709 !Existing.ContainsKey(Contact.BareJID))
712 Removed =
new LinkedList<KeyValuePair<string, TreeNode>>();
720 foreach (KeyValuePair<string, TreeNode> P
in Removed)
721 this.children.Remove(P.Key);
726 if (!(
Added is
null))
729 this.connections.Owner.MainView.NodeAdded(
this,
Node);
734 foreach (KeyValuePair<string, TreeNode> P
in Removed)
735 this.connections.Owner.MainView.NodeRemoved(
this, P.Value);
738 if (!(Resubscribe is
null))
744 if (!(Reunsubscribe is
null))
755 get {
return this.connections.Owner.MainView; }
758 private async Task Client_OnRosterItemUpdated(
object _,
RosterItem Item)
760 if (this.children is
null)
772 Contact.RosterItem =
Item;
776 Contact =
new XmppContact(
this, this.client,
Item.BareJid,
Item.IsInGroup(RemoteDesktopGroupName));
777 this.children[
Item.BareJid] = Contact;
784 this.connections.Owner.MainView.NodeAdded(
this, Contact);
790 await this.CheckRosterItemSubscriptions(
Item);
796 EventHandlerAsync<RosterItem>[] h;
798 lock (this.rosterSubscriptions)
800 if (this.rosterSubscriptions.TryGetValue(
Item.BareJid, out List<EventHandlerAsync<RosterItem>> List))
808 foreach (EventHandlerAsync<RosterItem> h2
in h)
809 await h2.Raise(
this,
Item);
813 public void RegisterRosterEventHandler(
string BareJid, EventHandlerAsync<RosterItem> Callback)
815 lock (this.rosterSubscriptions)
817 if (!this.rosterSubscriptions.TryGetValue(BareJid, out List<EventHandlerAsync<RosterItem>> h))
819 h =
new List<EventHandlerAsync<RosterItem>>();
820 this.rosterSubscriptions[BareJid] = h;
827 public void UnregisterRosterEventHandler(
string BareJid, EventHandlerAsync<RosterItem> Callback)
829 lock (this.rosterSubscriptions)
831 if (this.rosterSubscriptions.TryGetValue(BareJid, out List<EventHandlerAsync<RosterItem>> h) && h.Remove(Callback) && h.Count == 0)
832 this.rosterSubscriptions.Remove(BareJid);
836 private Task Client_OnRosterItemRemoved(
object _,
RosterItem Item)
838 if (this.children is
null)
852 return Task.CompletedTask;
857 if (this.children is
null)
876 else if (
string.Compare(e.
FromBareJID,
this.client.BareJID,
true) == 0)
877 await this.client.
Information(
"Presence from same bare JID. Ignored.");
879 await this.client.
Warning(
"Presence from node not found in roster: " + e.
FromBareJID);
883 await this.CheckRosterItemSubscriptions(
Item);
912 List<string> Groups =
new List<string>()
914 ConcentratorGroupName
918 Groups.
Add(EventsGroupName);
921 Groups.Add(RemoteDesktopGroupName);
923 this.AddGroups(
Node, Groups.ToArray());
939 List<string> Groups =
new List<string>()
945 Groups.
Add(SensorGroupName);
948 Groups.Add(EventsGroupName);
951 Groups.Add(RemoteDesktopGroupName);
953 this.AddGroups(
Node, Groups.ToArray());
968 List<string> Groups =
new List<string>()
974 Groups.
Add(EventsGroupName);
977 Groups.Add(RemoteDesktopGroupName);
979 this.AddGroups(
Node, Groups.ToArray());
993 List<string> Groups =
new List<string>()
999 Groups.
Add(RemoteDesktopGroupName);
1001 this.AddGroups(
Node, Groups.ToArray());
1007 return Task.CompletedTask;
1010 private void AddGroups(
XmppContact Contact, params
string[] GroupNames)
1012 string[] Groups = Contact.RosterItem.
Groups;
1016 foreach (
string GroupName
in GroupNames)
1018 if (Array.IndexOf<
string>(Groups, GroupName) < 0)
1021 Array.Resize<
string>(ref Groups, c + 1);
1022 Groups[c] = GroupName;
1030 Array.Sort<
string>(Groups);
1042 MainWindow.UpdateGui(this.PresenceSubscribe, e);
1045 private async Task PresenceSubscribe(
object P)
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))
1052 case MessageBoxResult.Yes:
1062 case MessageBoxResult.No:
1066 case MessageBoxResult.Cancel:
1078 public override bool CanRecycle
1080 get {
return !(this.client is
null); }
1085 if (!(this.children is
null))
1097 public bool IsOnline
1101 return !(this.client is
null) && this.client.
State ==
XmppState.Connected;
1105 public string BareJID
1109 if (this.client is
null)
1110 return string.Empty;
1116 public override string Key => this.BareJID;
1117 public override bool IsSniffable => !(this.client is
null);
1131 if (base.RemoveChild(
Node))
1139 catch (ArgumentException)
1151 public override void AddSniffer(Networking.Sniffers.ISniffer Sniffer)
1153 this.client.
Add(Sniffer);
1158 if (this.client is
null)
1159 return Task.FromResult(
false);
1161 return Task.FromResult(this.client.
Remove(Sniffer));
1166 this.client.OnChatMessage += Window.OnChatMessage;
1167 this.client.OnStateChanged += Window.OnStateChange;
1172 this.client.OnChatMessage -= Window.OnChatMessage;
1173 this.client.OnStateChanged -= Window.OnStateChange;
1176 public void SearchComponents()
1180 this.supportsSearch = e.HasFeature(XmppClient.NamespaceSearch);
1182 if (!this.supportsSearch)
1184 this.client.SendSearchFormRequest(string.Empty, (sender2, e2) =>
1187 this.supportsSearch = true;
1189 return Task.CompletedTask;
1194 return Task.CompletedTask;
1200 foreach (Item Item in e.Items)
1202 this.client.SendServiceDiscoveryRequest(Item.JID, async (sender2, e2) =>
1206 XmppComponent Component = null;
1207 ThingRegistry ThingRegistry = null;
1209 if (this.children is null)
1210 this.children = new SortedDictionary<string, TreeNode>();
1212 lock (this.children)
1214 if (this.children.ContainsKey(Item.JID))
1218 if (e2.HasAnyFeature(ThingRegistryClient.NamespacesDiscovery))
1220 ThingRegistry = new ThingRegistry(this, Item.JID, Item.Name, Item.Node, e2.Features);
1221 Component = ThingRegistry;
1223 else if (e2.HasFeature(PubSubClient.NamespacePubSub))
1225 this.AddPepClient(Item.JID);
1226 Component = new PubSubService(this, Item.JID, Item.Name, Item.Node, e2.Features, this.pepClient.PubSubClient);
1228 else if (e2.HasFeature(MultiUserChatClient.NamespaceMuc))
1230 this.AddMucClient(Item.JID);
1231 Component = new MucService(this, Item.JID, Item.Name, Item.Node, e2.Features, this.mucClient);
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);
1238 Component = new XmppComponent(this, Item.JID, Item.Name, Item.Node, e2.Features);
1240 lock (this.children)
1242 if (this.children.ContainsKey(Item.JID))
1244 Component.Dispose();
1248 this.children[Item.JID] = Component;
1251 this.connections.Owner.MainView.NodeAdded(this, Component);
1254 if (!(ThingRegistry is null) && ThingRegistry.SupportsProvisioning)
1256 MainWindow.UpdateGui(() =>
1258 MainWindow.currentInstance.NewQuestion(this, ThingRegistry.ProvisioningClient, null);
1259 return Task.CompletedTask;
1263 catch (Exception ex)
1271 return Task.CompletedTask;
1276 public override bool CanConfigure => this.IsOnline;
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))
1286 Title =
"Change password",
1287 Instructions =
new string[] {
"Enter the new password you wish to use." }
1297 string Password = Strings[0];
1299 if (Password.Length < 6)
1300 Field.Error =
"Password too short.";
1303 bool Digits =
false;
1307 foreach (
char ch
in Password)
1309 Digits |=
char.IsDigit(ch);
1310 Lower |=
char.IsLower(ch);
1311 Upper |=
char.IsUpper(ch);
1315 Field.Error =
"Password must contain digits.";
1317 Field.Error =
"Password must contain lower case characters.";
1319 Field.Error =
"Password must contain upper case characters.";
1328 string Password = Strings[0];
1330 if (Password !=
Field.
Form[
"Password"].ValueString)
1331 Field.Error =
"Passwords don't match.";
1335 private Task ChangePassword(
object _,
DataForm Form)
1337 string NewPassword = Form[
"Password"].ValueString;
1343 this.connections.Modified = true;
1344 this.passwordHash = string.Empty;
1345 this.client.Reconnect(this.client.UserName, NewPassword);
1347 MainWindow.SuccessBox(
"Password successfully changed.");
1350 MainWindow.ErrorBox(
"Unable to change password.");
1352 return Task.CompletedTask;
1356 return Task.CompletedTask;
1359 private Task CancelChangePassword(
object _,
DataForm _2)
1362 return Task.CompletedTask;
1365 public override bool CanReadSensorData => this.IsOnline;
1374 return this.DoReadout(
FieldType.Momentary);
1377 private async Task<SensorDataClientRequest> DoReadout(
FieldType Types)
1379 string Id = Guid.NewGuid().ToString();
1382 Types,
null, DateTime.MinValue, DateTime.MaxValue, DateTime.Now,
string.Empty,
string.Empty,
string.Empty);
1384 await Request.
Accept(
false);
1391 List<Waher.Things.SensorData.Field> Fields = new List<Waher.Things.SensorData.Field>();
1392 DateTime Now = DateTime.Now;
1394 foreach (KeyValuePair<string, bool> Feature in e.Features)
1396 Fields.Add(new Waher.Things.SensorData.BooleanField(Waher.Things.ThingReference.Empty, Now,
1397 Feature.Key, Feature.Value, FieldType.Momentary, FieldQoS.AutomaticReadout));
1400 bool VersionDone =
false;
1404 foreach (Identity Identity in e.Identities)
1406 Fields.Add(new StringField(Waher.Things.ThingReference.Empty, Now,
1407 Identity.Type, Identity.Category + (string.IsNullOrEmpty(Identity.Name) ? string.Empty :
" (" + Identity.Name +
")"),
1409 FieldQoS.AutomaticReadout));
1414 this.client.SendSoftwareVersionRequest(string.Empty, (sender2, e2) =>
1420 Request.LogFields(new Waher.Things.SensorData.Field[]
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),
1432 Request.LogErrors(new Waher.Things.ThingError[]
1434 new Waher.Things.ThingError(Waher.Things.ThingReference.Empty, Now,
"Unable to read software version.")
1443 return Task.CompletedTask;
1459 Request.
Fail(
"Unable to perform a service discovery.");
1461 return Task.CompletedTask;
1470 lock (this.components)
1472 if (!this.components.Contains(Component))
1473 this.components.AddLast(Component);
1479 lock (this.components)
1481 return this.components.Remove(Component);
1487 LinkedList<IMenuAggregator> Aggregators =
null;
1492 this.GroupSeparator(ref CurrentGroup,
"Connection", Menu);
1494 Menu.Items.Add(
Item =
new MenuItem()
1496 Header =
"_Change password...",
1497 IsEnabled = (!(this.client is
null) && this.client.
State ==
XmppState.Connected)
1500 Item.Click += this.ChangePassword_Click;
1503 lock (this.components)
1509 if (Aggregators is
null)
1510 Aggregators =
new LinkedList<IMenuAggregator>();
1512 Aggregators.AddLast(MenuAggregator);
1517 if (!(Aggregators is
null))
1524 private void ChangePassword_Click(
object Sender, RoutedEventArgs e)
1527 bool? Result = Dialog.ShowDialog();
1529 if (Result.HasValue && Result.Value)
1531 this.client.
ChangePassword(Dialog.Password.Password, (sender2, e2) =>
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);
1541 MainWindow.SuccessBox(
"Password successfully changed.");
1544 MainWindow.ErrorBox(
"Unable to change password.");
1546 return Task.CompletedTask;
1556 Owner = MainWindow.currentInstance
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;
1571 bool? Result = Dialog.ShowDialog();
1573 if (Result.HasValue && Result.Value)
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;
1581 this.trustCertificate = Dialog.TrustServerCertificate.IsChecked.HasValue && Dialog.TrustServerCertificate.IsChecked.Value;
1582 this.allowInsecureAuthentication = Dialog.AllowInsecureAuthentication.IsChecked.HasValue && Dialog.AllowInsecureAuthentication.IsChecked.Value;
1584 if (!
int.TryParse(Dialog.XmppPort.Text, out
this.port))
1614 return Task.CompletedTask;
1633 return Task.CompletedTask;
1647 return Task.CompletedTask;
1682 return Task.CompletedTask;
1697 return Task.CompletedTask;
1703 return Task.CompletedTask;
1715 if (this.e2eEncryption is
null)
1721 return e.Done(e2.Ok);
1728 lock (this.activeViews)
1730 this.activeViews[SessionId] = View;
1736 lock (this.activeViews)
1738 this.activeViews.Remove(View.Session.
SessionId);
1746 lock (this.activeViews)
1748 if (!this.activeViews.TryGetValue(e.
StreamId, out View))
1749 return Task.CompletedTask;
1752 e.
AcceptStream(View.Socks5DataReceived, View.Socks5StreamClosed,
null);
1754 return Task.CompletedTask;
1760 public override bool CanCopy => !(this.client is
null);
1767 Clipboard.SetText(
"xmpp:" + this.client.
BareJID);
1773 public override bool CanPaste
1777 return this.CanPasteFromClipboard(out _);
1781 private bool CanPasteFromClipboard(out
string BareJid)
1785 if (this.client is
null || this.client.
State !=
XmppState.Connected)
1788 if (!Clipboard.ContainsText(TextDataFormat.Text))
1791 string s = Clipboard.GetText(TextDataFormat.Text);
1792 if (!s.StartsWith(
"xmpp:"))
1808 if (this.CanPasteFromClipboard(out
string BareJid))
Interaction logic for App.xaml
Interaction logic for ConnectionView.xaml
Interaction logic for LogView.xaml
Represents one item in an event log output.
Interaction logic for RemoteDesktopView.xaml
Interaction logic for SnifferView.xaml
Interaction logic for xaml
Represents a node in a concentrator.
override void Add()
Is called when the user wants to add a node to the current node.
override string Key
Key in parent child collection.
override bool CanRecycle
If the node can be recycled.
Represents an XMPP concentrator.
Maintains the set of open connections.
Represents a simple XMPP actuator.
Represents a simple XMPP sensor.
Abstract base class for tree nodes in the connection view.
object Tag
Object tagged to the node.
TreeNode Parent
Parent node. May be null if a root node.
bool TryGetChild(string ChildKey, out TreeNode Child)
Tries to get the child node corresponding to a given key.
virtual Task Recycle(MainWindow Window)
Is called when the user wants to recycle the node.
virtual void OnUpdated()
Raises the Updated event.
EventHandler Updated
Raised when the node has been updated. The sender argument will contain a reference to the node.
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.
string Host
Host reference.
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 unspecialized XMPP contact.
Helps with parsing of commong data types.
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
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.
Event arguments for custom sniffer events.
Static class managing editable parameters in objects. Editable parameters are defined by using the at...
Event arguments for data source section events.
String-valued contractual parameter
Implements an XMPP control client interface.
static readonly string[] NamespacesControl
Supported control namespaces
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.
Edwards25519 Twisted Edwards Curve
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
Peer connection event arguments.
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.
Event argument for stream validation events.
bool AcceptStream(EventHandlerAsync< DataReceivedEventArgs > DataCallback, EventHandlerAsync< StreamEventArgs > CloseCallback, object State)
Call this method to accept the incoming stream.
Event argument for personal event notification events.
IPersonalEvent PersonalEvent
Parsed personal event, if appropriate type was found.
Event arguments for user activity events.
UserActivity Activity
User activity.
Event arguments for user location events.
UserLocation Location
User location.
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....
void RegisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Registers an event handler of a specific type of personal events.
override void Dispose()
Disposes of the extension.
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
string Text
Custom text provided by the use.
string Title
The title of the song or piece
byte? Rating
The user's rating of the song or piece, from 1 (lowest) to 10 (highest).
Uri Uri
A URI or URL pointing to information about the song, collection, or artist
string Track
A unique identifier for the tune; e.g., the track number within a collection or the specific URI for ...
string Source
The collection (e.g., album) or other source (e.g., a band website that hosts streams or audio files)
ushort? Length
The duration of the song or piece in seconds
string Artist
The artist or performer of the song or piece
override void Dispose()
Disposes of the extension.
const string RemoteDesktopNamespace
http://waher.se/rdp/1.0
string SessionId
Session ID
Maintains information about an item in the roster.
string[] Groups
Any groups the roster item belongs to.
string Name
Name of the roster item.
Manages a sensor data client request.
new Task LogFields(IEnumerable< Field > Fields)
Fields logged.
new Task Started()
Readout started.
new Task Fail(string Reason)
Readout failed.
new Task Accept(bool Queued)
Readout accepted.
new void Done()
Readout complete.
Implements an XMPP sensor client interface.
static readonly string[] NamespacesSensorEvents
Supported sensor event namespaces.
override void Dispose()
Disposes of the extension.
static readonly string[] NamespacesSensorData
Supported sensor-data namespaces.
Contains personal sensor data.
IEnumerable< Field > Fields
Sensor data fields.
Contains information about an item of an entity.
Event arguments for service discovery responses.
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....
void Dispose()
IDisposable.Dispose()
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Task ChangePassword(string NewPassword)
Changes the password of the current user.
XmppState State
Current state of connection.
Task OfflineAndDisposeAsync()
Sends an offline presence, and then disposes the object by calling DisposeAsync.
Task RemoveRosterItem(string BareJID)
Removes an item from the roster.
const string NamespaceSoftwareVersion
jabber:iq:version
Task UpdateRosterItem(string BareJID, string Name, params string[] Groups)
Updates an item in the roster.
Task RequestPresenceSubscription(string BareJid)
Requests subscription of presence information from a contact.
string PasswordHashMethod
Password hash method.
static readonly Regex BareJidRegEx
Regular expression for Bare JIDs
async Task Reconnect()
Reconnects a client after an error or if it's offline. Reconnecting, instead of creating a completely...
Task RequestPresenceUnsubscription(string BareJid)
Requests unssubscription of presence information from a contact.
bool RemoveTag(string TagName)
Removes a tag from the client.
void SetTag(string TagName, object Tag)
Sets a tag value.
Task SendServiceDiscoveryRequest(string To, EventHandlerAsync< ServiceDiscoveryEventArgs > Callback, object State)
Sends a service discovery request
string PasswordHash
Hash value of password. Depends on method used to authenticate user.
Task Connect()
Connects the client.
string Domain
Current Domain.
Task SendServiceItemsDiscoveryRequest(string To, EventHandlerAsync< ServiceItemsDiscoveryEventArgs > Callback, object State)
Sends a service items discovery request
Task SetPresence()
Sets the presence of the connection. Add a CustomPresenceXml event handler to add custom presence XML...
RosterItem[] Roster
Items in the roster.
RosterItem GetRosterItem(string BareJID)
Gets a roster item.
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.
Base class for all sensor data fields.
Represents a 32-bit integer value.
Represents a 64-bit integer value.
Interface for objects that contain a reference to a host.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Availability
Resource availability.
SubscriptionState
State of a presence subscription.
XmppState
State of XMPP connection.
PendingSubscription
Pending subscription states.
FieldType
Field Type flags