private async void Client_OnStateChanged(object Sender, XmppState NewState) { if (!(Sender is XmppClient Client)) { return; } if (!Client.TryGetTag("TabID", out object Obj) || !(Obj is string TabID)) { return; } try { string Msg; switch (NewState) { case XmppState.Authenticating: Client.SetTag("StartedAuthentication", true); Client.SetTag("EncyptionSuccessful", true); if (this.Step == 0) { ClientEvents.PushEvent(new string[] { TabID }, "ConnectionOK0", "Connection established.", false, "User"); this.client.Dispose(); this.client = null; this.Step = 1; this.Updated = DateTime.Now; await Database.Update(this); return; } else { Msg = "Authenticating user."; } break; case XmppState.Binding: Msg = "Binding to resource."; break; case XmppState.Connected: this.bareJid = Client.BareJID; if (this.createAccount && !string.IsNullOrEmpty(this.accountHumanReadableName)) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Setting vCard.", false, "User"); StringBuilder Xml = new StringBuilder(); Xml.Append("<vCard xmlns='vcard-temp'>"); Xml.Append("<FN>"); Xml.Append(XML.Encode(this.accountHumanReadableName)); Xml.Append("</FN>"); Xml.Append("<JABBERID>"); Xml.Append(XML.Encode(this.client.BareJID)); Xml.Append("</JABBERID>"); Xml.Append("</vCard>"); await Client.IqSetAsync(this.client.BareJID, Xml.ToString()); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking server features.", false, "User"); ServiceDiscoveryEventArgs e = await Client.ServiceDiscoveryAsync(null, string.Empty, string.Empty); if (e.Ok) { this.offlineMessages = e.HasFeature("msgoffline"); this.blocking = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceBlocking); this.reporting = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceReporting); this.abuse = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceAbuseReason); this.spam = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceSpamReason); this.mail = e.HasFeature("urn:xmpp:smtp"); } else { this.offlineMessages = false; this.blocking = false; this.reporting = false; this.abuse = false; this.spam = false; this.mail = false; } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking account features.", false, "User"); e = await Client.ServiceDiscoveryAsync(null, Client.BareJID, string.Empty); this.pep = e.Ok && this.ContainsIdentity("pep", "pubsub", e); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking server components.", false, "User"); ServiceItemsDiscoveryEventArgs e2 = await Client.ServiceItemsDiscoveryAsync(null, string.Empty, string.Empty); this.thingRegistry = string.Empty; this.provisioning = string.Empty; this.events = string.Empty; this.pubSub = string.Empty; this.legal = string.Empty; this.software = string.Empty; if (e2.Ok) { foreach (Item Item in e2.Items) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking component features for " + Item.JID, false, "User"); e = await Client.ServiceDiscoveryAsync(null, Item.JID, string.Empty); if (e.HasFeature(Networking.XMPP.Provisioning.ThingRegistryClient.NamespaceDiscovery)) { this.thingRegistry = Item.JID; } if (e.HasFeature(Networking.XMPP.Provisioning.ProvisioningClient.NamespaceProvisioningDevice)) { this.provisioning = Item.JID; } if (e.HasFeature(Networking.XMPP.PubSub.PubSubClient.NamespacePubSub) && this.ContainsIdentity("service", "pubsub", e)) { this.pubSub = Item.JID; } if (e.HasFeature(Waher.Events.XMPP.XmppEventSink.NamespaceEventLogging)) { this.events = Item.JID; } if (e.HasFeature(Networking.XMPP.Contracts.ContractsClient.NamespaceLegalIdentities)) { this.legal = Item.JID; } if (e.HasFeature(Networking.XMPP.Software.SoftwareUpdateClient.NamespaceSoftwareUpdates)) { this.software = Item.JID; } } } Dictionary <string, object> ConnectionInfo = new Dictionary <string, object>() { { "msg", "Connection successful." }, { "offlineMsg", this.offlineMessages }, { "blocking", this.blocking }, { "reporting", this.reporting }, { "abuse", this.abuse }, { "spam", this.spam }, { "mail", this.mail }, { "pep", this.pep ? this.bareJid : string.Empty }, { "thingRegistry", this.thingRegistry }, { "provisioning", this.provisioning }, { "eventLog", this.events }, { "pubSub", this.pubSub }, { "legal", this.legal }, { "software", this.software } }; ClientEvents.PushEvent(new string[] { TabID }, "ConnectionOK1", JSON.Encode(ConnectionInfo, false), true, "User"); this.client.Dispose(); this.client = null; this.Step = 2; this.Updated = DateTime.Now; await Database.Update(this); return; case XmppState.Connecting: Msg = "Connecting to server."; break; case XmppState.Error: bool Error = false; Msg = string.Empty; if (this.Step == 0 && this.transportMethod == XmppTransportMethod.C2S) { this.customBinding = true; ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Unable to connect properly. Looking for alternative ways to connect.", false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowCustomProperties", "{\"visible\":true}", true, "User"); using (HttpClient HttpClient = new HttpClient(new HttpClientHandler() { #if !NETFW ServerCertificateCustomValidationCallback = this.RemoteCertificateValidationCallback, #endif UseCookies = false }) { Timeout = TimeSpan.FromMilliseconds(60000) }) { try { HttpResponseMessage Response = await HttpClient.GetAsync("http://" + this.host + "/.well-known/host-meta"); Response.EnsureSuccessStatusCode(); Stream Stream = await Response.Content.ReadAsStreamAsync(); // Regardless of status code, we check for XML content. byte[] Bin = await Response.Content.ReadAsByteArrayAsync(); string CharSet = Response.Content.Headers.ContentType.CharSet; Encoding Encoding; if (string.IsNullOrEmpty(CharSet)) { Encoding = Encoding.UTF8; } else { Encoding = InternetContent.GetEncoding(CharSet); } string XmlResponse = Encoding.GetString(Bin); XmlDocument Doc = new XmlDocument(); Doc.LoadXml(XmlResponse); if (Doc.DocumentElement != null && Doc.DocumentElement.LocalName == "XRD") { string BoshUrl = null; string WsUrl = null; foreach (XmlNode N in Doc.DocumentElement.ChildNodes) { if (N is XmlElement E && E.LocalName == "Link") { switch (XML.Attribute(E, "rel")) { case "urn:xmpp:alt-connections:xbosh": BoshUrl = XML.Attribute(E, "href"); break; case "urn:xmpp:alt-connections:websocket": WsUrl = XML.Attribute(E, "href"); break; } } } if (!string.IsNullOrEmpty(WsUrl)) { this.wsUrl = WsUrl; this.transportMethod = XmppTransportMethod.WS; ClientEvents.PushEvent(new string[] { TabID }, "ShowTransport", "{\"method\":\"WS\"}", true, "User"); this.Connect(TabID); return; } else if (!string.IsNullOrEmpty(BoshUrl)) { this.boshUrl = BoshUrl; this.transportMethod = XmppTransportMethod.BOSH; ClientEvents.PushEvent(new string[] { TabID }, "ShowTransport", "{\"method\":\"BOSH\"}", true, "User"); this.Connect(TabID); return; } } } catch (Exception) { // Ignore. } Msg = "No alternative binding methods found."; Error = true; } } else { Msg = "Unable to connect properly."; Error = true; if (Client.TryGetTag("StartedAuthentication", out Obj) && Obj is bool b && b) { if (this.createAccount) { ClientEvents.PushEvent(new string[] { TabID }, "ShowFail2", Msg, false, "User"); } else { ClientEvents.PushEvent(new string[] { TabID }, "ShowFail1", Msg, false, "User"); } return; } } if (Error) { ClientEvents.PushEvent(new string[] { TabID }, "ConnectionError", Msg, false, "User"); this.client.Dispose(); this.client = null; return; } break; case XmppState.FetchingRoster: Msg = "Fetching roster from server."; break; case XmppState.Offline: Msg = "Offline."; break; case XmppState.Registering: Msg = "Registering account."; break; case XmppState.RequestingSession: Msg = "Requesting session."; break; case XmppState.SettingPresence: Msg = "Setting presence."; break; case XmppState.StartingEncryption: Msg = "Starting encryption."; Client.SetTag("StartedEncryption", true); break; case XmppState.StreamNegotiation: Msg = "Negotiating stream."; break; case XmppState.StreamOpened: Msg = "Stream opened."; break; default: Msg = NewState.ToString(); break; } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", Msg, false, "User"); } catch (Exception ex) { Log.Critical(ex); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", ex.Message, false, "User"); } }
private void ConnectToHost(HttpRequest Request, HttpResponse Response) { Gateway.AssertUserAuthenticated(Request); if (!Request.HasData) { throw new BadRequestException(); } object Obj = Request.DecodeData(); if (!(Obj is Dictionary <string, object> Parameters)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("host", out Obj) || !(Obj is string HostName)) { throw new BadRequestException(); } string TabID = Request.Header["X-TabID"]; if (string.IsNullOrEmpty(TabID)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("port", out Obj) || !(Obj is int Port) || Port < 1 || Port > 65535) { throw new BadRequestException(); } if (!Parameters.TryGetValue("boshUrl", out Obj) || !(Obj is string BoshUrl)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("wsUrl", out Obj) || !(Obj is string WsUrl)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("customBinding", out Obj) || !(Obj is bool CustomBinding)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("trustServer", out Obj) || !(Obj is bool TrustServer)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("insecureMechanisms", out Obj) || !(Obj is bool InsecureMechanisms)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("storePassword", out Obj) || !(Obj is bool StorePasswordInsteadOfHash)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("sniffer", out Obj) || !(Obj is bool Sniffer)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("transport", out Obj) || !(Obj is string s2) || !Enum.TryParse <XmppTransportMethod>(s2, out XmppTransportMethod Method)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("account", out Obj) || !(Obj is string Account)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("password", out Obj) || !(Obj is string Password)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("createAccount", out Obj) || !(Obj is bool CreateAccount)) { throw new BadRequestException(); } if (!Parameters.TryGetValue("accountName", out Obj) || !(Obj is string AccountName)) { throw new BadRequestException(); } this.host = HostName; this.port = Port; this.boshUrl = BoshUrl.Trim(); this.wsUrl = WsUrl.Trim(); this.customBinding = CustomBinding; this.trustServer = TrustServer; this.allowInsecureMechanisms = InsecureMechanisms; this.storePasswordInsteadOfHash = StorePasswordInsteadOfHash; this.sniffer = Sniffer; this.transportMethod = Method; this.account = Account; this.createAccount = CreateAccount; this.accountHumanReadableName = AccountName; if (this.password != Password) { this.password = Password; this.passwordType = string.Empty; } if (this.client != null) { this.client.Dispose(); this.client = null; } Response.StatusCode = 200; this.Connect(TabID); }