public void IdentityTests() { var info = new DiscoInfo { Identity = new Identity { IdentityName = "SharpXMPP", IdentityType = "pc", Category = "client" }, Features = new List <string> { Namespaces.DiscoInfo } }; var cf = new XElement(XNamespace.Get("storage:bookmarks") + "conference"); cf.SetAttributeValue("jid", "*****@*****.**"); cf.SetAttributeValue("name", "lalallaa"); cf.SetAttributeValue("autojoin", "false"); var room = Stanza.Parse <BookmarkedConference>(cf); Assert.IsFalse(room.IsAutojoin); var cf2 = new XElement(XNamespace.Get("storage:bookmarks") + "conference"); cf2.SetAttributeValue("jid", "*****@*****.**"); cf2.SetAttributeValue("name", "lalallaa"); cf2.SetAttributeValue("autojoin", "1"); var room2 = Stanza.Parse <BookmarkedConference>(cf2); Assert.IsTrue(room2.IsAutojoin); }
public override void SessionLoop() { while (true) { try { var el = NextElement(); if (el.Name.LocalName.Equals("iq")) { OnIq(Stanza.Parse <XMPPIq>(el)); } if (el.Name.LocalName.Equals("message")) { OnMessage(Stanza.Parse <XMPPMessage>(el)); } if (el.Name.LocalName.Equals("presence")) { OnPresence(Stanza.Parse <XMPPPresence>(el)); } } catch (Exception e) { OnConnectionFailed(new ConnFailedArgs { Message = e.Message }); break; } } }
public static void BookmarksManagerSendsThePasswordToJoin() { using var stream = new MemoryStream(); using var connection = new MockedXmppTcpConnection(null, stream); var elements = new List <XElement>(); connection.Element += (_, element) => elements.Add(element.Stanza); var conference = new BookmarkedConference { JID = new JID("*****@*****.**"), Password = "******" }; var bookmarksManager = new BookmarksManager(connection, false); bookmarksManager.Join(conference); Thread.MemoryBarrier(); var joinElement = Stanza.Parse <XMPPPresence>(elements.Single()); var password = joinElement .Element(XNamespace.Get(Namespaces.MUC) + "x") ! .Element(XNamespace.Get(Namespaces.MUC) + "password") ! .Value; Assert.AreEqual("12345", password); }
public BookmarksManager(XmppConnection conn, bool autoAsk = true) { connection = conn; connection.SignedIn += (sender, e) => { if (autoAsk) { var query = new XMPPIq(XMPPIq.IqTypes.get); var priv = new XElement(XNamespace.Get("jabber:iq:private") + "query", new XElement(XNamespace.Get(Namespaces.StorageBookmarks) + "storage") ); query.Add(priv); connection.Query(query, (response) => { var roomsXML = response.Element(XNamespace.Get("jabber:iq:private") + "query") .Element(XNamespace.Get(Namespaces.StorageBookmarks) + "storage") .Elements(XNamespace.Get(Namespaces.StorageBookmarks) + "conference"); foreach (var roomObj in roomsXML) { var room = Stanza.Parse <BookmarkedConference>(roomObj); Rooms.Add(room); if (room.IsAutojoin) { Join(room); } } OnBookmarksSynced(conn); }); } }; }
public void Start(XmppTcpConnection connection) { connection.Features = Stanza.Parse <Features>(connection.NextElement()); if (connection.Features.Bind) { var bind = new Elements.Bind(connection.Jid.Resource); var iq = new XMPPIq(XMPPIq.IqTypes.set); iq.Add(bind); connection.Query(iq, (bindResult) => { var jid = bindResult.Element(XNamespace.Get(Namespaces.XmppBind) + "bind"); if (jid == null) { return; } connection.Jid = new JID(jid.Element(XNamespace.Get(Namespaces.XmppBind) + "jid").Value); if (connection.Features.Session) { var sess = new XElement(XNamespace.Get(Namespaces.XmppSession) + "session"); var sessIq = new XMPPIq(XMPPIq.IqTypes.set); sessIq.Add(sess); connection.Query(sessIq, (sessionResponse) => OnSessionStarted(connection)); } else { OnSessionStarted(connection); } }); connection.SessionLoop(); } }
public override bool Handle(XmppConnection sender, XMPPIq element) { if (Stanza.Parse <DiscoItems>(element.Elements().FirstOrDefault()) != null) { sender.Send(element.Reply()); return(true); } return(false); }
private async Task <bool> InitTlsIfSupported(Features features) { if (!features.Tls) { return(false); } Send(new StartTLS()); var res = Stanza.Parse <Proceed>(NextElement()); if (res == null) { return(false); } ConnectionStream = new SslStream(ConnectionStream, true); await((SslStream)ConnectionStream).AuthenticateAsClientAsync(Jid.Domain); RestartXmlStreams(); return(true); }
public override bool Handle(XmppConnection connection, XMPPIq element) { var info = Stanza.Parse <DiscoInfo>(element.Elements().FirstOrDefault()); if (info != null) { if (info.Node == string.Empty || info.Node == string.Format("{0}#{1}", _capabilities.Node, _capabilities.OurHash)) { info.Identity = _capabilities.Identity; info.Features = _capabilities.Features; info.Node = _capabilities.Node; var reply = element.Reply(); reply.RemoveNodes(); reply.Add(info); connection.Send(reply); return(true); } } return(false); }
public override Task SessionLoopAsync(CancellationToken token) { return(Task.Run(() => { while (!token.IsCancellationRequested) { try { var el = NextElement(); token.ThrowIfCancellationRequested(); if (el.Name.LocalName.Equals("iq")) { token.ThrowIfCancellationRequested(); OnIq(Stanza.Parse <XMPPIq>(el)); } if (el.Name.LocalName.Equals("message")) { token.ThrowIfCancellationRequested(); OnMessage(Stanza.Parse <XMPPMessage>(el)); } if (el.Name.LocalName.Equals("presence")) { token.ThrowIfCancellationRequested(); OnPresence(Stanza.Parse <XMPPPresence>(el)); } } catch (OperationCanceledException) { break; } catch (Exception e) { OnConnectionFailed(new ConnFailedArgs { Message = e.Message }); break; } } }, token)); }
public void StanzaTests() { const string xmldata = "<stream:error xmlns:stream=\"http://etherx.jabber.org/streams\"><not-well-formed xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\" /></stream:error>"; var errorinput = XElement.Parse(xmldata); var payload = Stanza.Parse <StreamError>(errorinput); Assert.AreEqual(StreamErrorType.NotWellFormed, payload.ErrorType); var error = new StreamError { ErrorType = StreamErrorType.NotWellFormed }; // Remove all namespace attributes. error.DescendantsAndSelf().Attributes().Where(n => n.IsNamespaceDeclaration).Remove(); // Specify that the namespace will be serialized with a namespace prefix of 'stream'. error.Add(new XAttribute(XNamespace.Xmlns + "stream", Namespaces.Streams)); Assert.AreEqual(payload.ToString(), Stanza.Parse <StreamError>(XElement.Parse(error.ToString())).ToString()); var bad = Stanza.Parse <StartTLS>(errorinput); Assert.IsNull(bad); }
public RosterManager(XmppConnection conn, bool autoAsk = true) { Roster = new ObservableCollection <RosterItem>(); conn.SignedIn += (sender, e) => { if (autoAsk) { var query = new XMPPIq(XMPPIq.IqTypes.get); query.Add(new XElement(XNamespace.Get(Namespaces.JabberRoster) + "query")); conn.Query(query, (response) => { var roster = response.Element(XNamespace.Get(Namespaces.JabberRoster) + "query") .Elements(XNamespace.Get(Namespaces.JabberRoster) + "item"); foreach (var item in roster) { Roster.Add(Stanza.Parse <RosterItem>(item)); } OnRosterUpdated(conn); }); } }; }
public override async void Connect() { List <IPAddress> HostAddresses = new List <IPAddress>(); var srvs = await Resolver.ResolveXMPPClient(Jid.Domain); if (srvs.Any()) { foreach (var srv in srvs) { var addresses = await Dns.GetHostAddressesAsync(srv.Host); HostAddresses.AddRange(addresses); } } else { HostAddresses.AddRange(await Dns.GetHostAddressesAsync(Jid.Domain)); } _client = new TcpClient(); await _client.ConnectAsync(HostAddresses.ToArray(), TcpPort); // TODO: check ports ConnectionStream = _client.GetStream(); Iq += (sender, iq) => new IqManager(this) { PayloadHandlers = new List <PayloadHandler> { new InfoHandler(Capabilities), new ItemsHandler() } }.Handle(iq); RestartXmlStreams(); var features = Stanza.Parse <Features>(NextElement()); if (features.Tls) { Send(new StartTLS()); var res = Stanza.Parse <Proceed>(NextElement()); if (res != null) { ConnectionStream = new SslStream(ConnectionStream, true); await((SslStream)ConnectionStream).AuthenticateAsClientAsync(Jid.Domain); RestartXmlStreams(); features = Stanza.Parse <Features>(NextElement()); } } var authenticator = SASLHandler.Create(features.SaslMechanisms, Jid, Password); if (authenticator == null) { OnConnectionFailed(new ConnFailedArgs { Message = "supported sasl mechanism not available" }); return; } authenticator.Authenticated += sender => { RestartXmlStreams(); var session = new SessionHandler(); session.SessionStarted += connection => OnSignedIn(new SignedInArgs { Jid = connection.Jid }); session.Start(this); }; authenticator.AuthenticationFailed += sender => { OnConnectionFailed(new ConnFailedArgs { Message = "Authentication failed" }); return; }; authenticator.Start(this); }
private Features GetServerFeatures() => Stanza.Parse <Features>(NextElement());
public void ReadStreamStart(string data, string defaultNamespace = Namespaces.JabberClient) { var mngr = Stanza.Parse <Open>(XElement.Parse(data)); OnStreamStart(mngr.ID); }
public override Task ConnectAsync(CancellationToken token) { return(Task.Run(async() => { if (string.IsNullOrEmpty(websocketUri)) { var lookup = new LookupClient(); var response = await lookup.QueryAsync("_xmppconnect." + Jid.Domain, QueryType.TXT); if (response.Answers.TxtRecords().Any()) { foreach (var srv in response.Answers.TxtRecords()) { foreach (var addr in srv.Text) { if (addr.StartsWith("_xmpp-client-websocket")) { websocketUri = addr.Split('=')[1]; break; } } } } } if (string.IsNullOrEmpty(websocketUri)) { OnConnectionFailed(new ConnFailedArgs { Message = "WebSocket URI is not resolved or set." }); return; } _connection = new WebSocket(websocketUri, "xmpp", WebSocketVersion.Rfc6455); _connection.Opened += (sender, args) => { _currentState = XmppConnectionState.Connected; RestartStream(); }; _connection.MessageReceived += (sender, args) => { OnElement(new ElementArgs { IsInput = true, Stanza = XElement.Parse(args.Message) }); if (_currentState == XmppConnectionState.Connected) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamInitiated; } else if (_currentState == XmppConnectionState.StreamAuthenticated) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamResourceBindingRequest; } else { var currentStanza = XElement.Parse(args.Message); var error = Stanza.Parse <StreamError>(currentStanza); if (error != null) { OnConnectionFailed(new ConnFailedArgs { Message = error.Value }); return; } switch (_currentState) { case XmppConnectionState.StreamInitiated: var features = Stanza.Parse <Features>(currentStanza); authenticator = SASLHandler.Create(features.SaslMechanisms, Jid, Password); if (authenticator == null) { OnConnectionFailed(new ConnFailedArgs { Message = "supported sasl mechanism not available" }); return; } var auth = new SASLAuth(); auth.SetAttributeValue("mechanism", authenticator.SASLMethod); var authInit = authenticator.Initiate(); if (!string.IsNullOrEmpty(authInit)) { auth.SetValue(authInit); } Send(auth); _currentState = XmppConnectionState.StreamAuthenticating; break; case XmppConnectionState.StreamAuthenticating: switch (currentStanza.Name.LocalName) { case "success": _currentState = XmppConnectionState.StreamAuthenticated; RestartStream(); break; case "failure": OnConnectionFailed(new ConnFailedArgs { Message = currentStanza.Value }); _currentState = XmppConnectionState.Disconnected; return; case "challenge": var response = new SASLResponse(); response.SetValue( authenticator.NextChallenge(currentStanza.Value)); Send(response); break; } break; case XmppConnectionState.StreamResourceBindingRequest: // todo: parse features of negotiated stream //Stanza.Parse<Features>(currentStanza); var bind = new Bind(Jid.Resource); var iq = new XMPPIq(XMPPIq.IqTypes.set); iq.Add(bind); Send(iq); _currentState = XmppConnectionState.StreamResourceBindingResponse; break; case XmppConnectionState.StreamResourceBindingResponse: var bindedJid = currentStanza.Element( XNamespace.Get(Namespaces.XmppBind) + "bind"); if (bindedJid == null) { OnConnectionFailed(new ConnFailedArgs { Message = "bind failed" }); _currentState = XmppConnectionState.Disconnected; } else { var sess = new XElement( XNamespace.Get(Namespaces.XmppSession) + "session"); var sessIq = new XMPPIq(XMPPIq.IqTypes.set); sessIq.Add(sess); Send(sessIq); _currentState = XmppConnectionState.StreamSessionNoOp; Jid = new JID( bindedJid.Element( XNamespace.Get(Namespaces.XmppBind) + "jid") .Value); } break; case XmppConnectionState.StreamSessionNoOp: OnSignedIn(new SignedInArgs { Jid = Jid }); _currentState = XmppConnectionState.StreamNegotiated; break; case XmppConnectionState.StreamNegotiated: if (currentStanza.Name.LocalName.Equals("iq")) { OnIq(Stanza.Parse <XMPPIq>(currentStanza)); } if (currentStanza.Name.LocalName.Equals("message")) { OnMessage(Stanza.Parse <XMPPMessage>(currentStanza)); } if (currentStanza.Name.LocalName.Equals("presence")) { OnPresence(Stanza.Parse <XMPPPresence>(currentStanza)); } break; default: throw new IOException("Invalid state"); } } }; _connection.Open(); })); }
public XmppWebSocketConnection(JID jid, string password, string websocketUri) : base(jid, password) { Capabilities = new CapabilitiesManager { Identity = new Identity { Category = "client", IdentityType = "mobile", IdentityName = "SharpXMPP" }, Node = "http://bggg.net.ru/caps", Features = new List <string> { Namespaces.DiscoInfo, Namespaces.DiscoItems } }; IqTracker = new XMPP.Client.IqHandler(this) { ResponseHandlers = new Dictionary <string, ResponseHandler>(), PayloadHandlers = new List <PayloadHandler> { new InfoHandler(Capabilities), new ItemsHandler() } }; Iq += (sender, iq) => IqTracker.Handle(iq); // ReSharper disable RedundantArgumentDefaultValue _connection = new WebSocket(websocketUri, "xmpp", cookies: (List <KeyValuePair <string, string> >)null); // ReSharper restore RedundantArgumentDefaultValue _connection.Opened += (sender, args) => { _currentState = XmppConnectionState.Connected; RestartStream(); }; _connection.MessageReceived += (sender, args) => { if (_currentState == XmppConnectionState.Connected) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamInitiated; } else if (_currentState == XmppConnectionState.StreamAuthenticated) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamResourceBindingRequest; } else { var currentStanza = Stanza.Parse(args.Message); OnElement(new ElementArgs { IsInput = false, Stanza = currentStanza }); var error = Stanza.Parse <StreamError>(currentStanza); if (error != null) { OnConnectionFailed(new ConnFailedArgs { Message = error.Value }); return; } switch (_currentState) { case XmppConnectionState.StreamInitiated: var features = Stanza.Parse <Features>(currentStanza); authenticator = SASLHandler.Create(features.SaslMechanisms, Jid, Password); if (authenticator == null) { OnConnectionFailed(new ConnFailedArgs { Message = "supported sasl mechanism not available" }); return; } var auth = new SASLAuth(); auth.SetAttributeValue("mechanism", authenticator.SASLMethod); var authInit = authenticator.Initiate(); if (!string.IsNullOrEmpty(authInit)) { auth.SetValue(authInit); } Send(auth); _currentState = XmppConnectionState.StreamAuthenticating; break; case XmppConnectionState.StreamAuthenticating: switch (currentStanza.Name.LocalName) { case "success": _currentState = XmppConnectionState.StreamAuthenticated; RestartStream(); break; case "failure": OnConnectionFailed(new ConnFailedArgs { Message = currentStanza.Value }); _currentState = XmppConnectionState.Disconnected; return; case "challenge": var response = new SASLResponse(); response.SetValue( authenticator.NextChallenge(currentStanza.Value)); Send(response); break; } break; case XmppConnectionState.StreamResourceBindingRequest: // todo: parse features of negotiated stream //Stanza.Parse<Features>(currentStanza); var bind = new Bind(Jid.Resource); var iq = new Iq(XMPP.Client.Elements.Iq.IqTypes.set); iq.Add(bind); Send(iq); _currentState = XmppConnectionState.StreamResourceBindingResponse; break; case XmppConnectionState.StreamResourceBindingResponse: var bindedJid = currentStanza.Element( XNamespace.Get(Namespaces.XmppBind) + "bind"); if (bindedJid == null) { OnConnectionFailed(new ConnFailedArgs { Message = "bind failed" }); _currentState = XmppConnectionState.Disconnected; } else { var sess = new XElement( XNamespace.Get(Namespaces.XmppSession) + "session"); var sessIq = new Iq(XMPP.Client.Elements.Iq.IqTypes.set); sessIq.Add(sess); Send(sessIq); _currentState = XmppConnectionState.StreamSessionNoOp; Jid = new JID( bindedJid.Element( XNamespace.Get(Namespaces.XmppBind) + "jid") .Value); } break; case XmppConnectionState.StreamSessionNoOp: OnSignedIn(new SignedInArgs { Jid = Jid }); Roster.Query(this); var initPresence = new Presence(Capabilities); Send(initPresence); _currentState = XmppConnectionState.StreamNegotiated; break; case XmppConnectionState.StreamNegotiated: if (currentStanza.Name.LocalName.Equals("iq")) { OnIq(Stanza.Parse <Iq>(currentStanza)); } if (currentStanza.Name.LocalName.Equals("message")) { OnMessage(Stanza.Parse <Message>(currentStanza)); } break; default: throw new IOException("Invalid state"); } } }; }