diff --git a/xmpp-vala/src/module/xep/0166_jingle.vala b/xmpp-vala/src/module/xep/0166_jingle.vala index a251293d..351d8e0c 100644 --- a/xmpp-vala/src/module/xep/0166_jingle.vala +++ b/xmpp-vala/src/module/xep/0166_jingle.vala @@ -102,16 +102,20 @@ ContentNode get_single_content_node(StanzaNode jingle) throws IqError { }; } +// This module can only be attached to one stream at a time. public class Module : XmppStreamModule, Iq.Handler { public static Xmpp.ModuleIdentity IDENTITY = new Xmpp.ModuleIdentity(NS_URI, "0166_jingle"); private HashMap content_types = new HashMap(); private HashMap transports = new HashMap(); + private XmppStream? current_stream = null; + public override void attach(XmppStream stream) { stream.add_flag(new Flag()); stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI); stream.get_module(Iq.Module.IDENTITY).register_for_namespace(NS_URI, this); + current_stream = stream; } public override void detach(XmppStream stream) { } @@ -173,7 +177,7 @@ public class Module : XmppStreamModule, Iq.Handler { throw new Error.GENERAL("Couldn't determine own JID"); } TransportParameters transport_params = transport.create_transport_parameters(stream, my_jid, receiver_full_jid); - Session session = new Session.initiate_sent(random_uuid(), type, transport_params, my_jid, receiver_full_jid, content_name, stream); + Session session = new Session.initiate_sent(random_uuid(), type, transport_params, my_jid, receiver_full_jid, content_name, send_terminate_and_remove_session); StanzaNode content = new StanzaNode.build("content", NS_URI) .put_attribute("creator", "initiator") .put_attribute("name", content_name) @@ -221,20 +225,34 @@ public class Module : XmppStreamModule, Iq.Handler { ContentParameters content_params = content_type.parse_content_parameters(content.description); TransportType type = content_type.content_type_transport_type(); - Session session = new Session.initiate_received(sid, type, transport_params, my_jid, iq.from, content.name, stream); + Session session = new Session.initiate_received(sid, type, transport_params, my_jid, iq.from, content.name, send_terminate_and_remove_session); stream.get_flag(Flag.IDENTITY).add_session(session); stream.get_module(Iq.Module.IDENTITY).send_iq(stream, new Iq.Stanza.result(iq)); if (transport == null || transport.transport_type() != type) { StanzaNode reason = new StanzaNode.build("reason", NS_URI) .put_node(new StanzaNode.build("unsupported-transports", NS_URI)); - session.terminate(stream, reason, "unsupported transports"); + session.terminate(reason, "unsupported transports"); return; } content_params.on_session_initiate(stream, session); } + private void send_terminate_and_remove_session(Jid to, string sid, StanzaNode reason) { + StanzaNode jingle = new StanzaNode.build("jingle", NS_URI) + .add_self_xmlns() + .put_attribute("action", "session-terminate") + .put_attribute("sid", sid) + .put_node(reason); + Iq.Stanza iq = new Iq.Stanza.set(jingle) { to=to }; + current_stream.get_module(Iq.Module.IDENTITY).send_iq(current_stream, iq); + + // Immediately remove the session from the open sessions as per the + // XEP, don't wait for confirmation. + current_stream.get_flag(Flag.IDENTITY).remove_session(sid); + } + public void on_iq_set(XmppStream stream, Iq.Stanza iq) { try { handle_iq_set(stream, iq); @@ -294,6 +312,8 @@ public enum Senders { } } +public delegate void SessionTerminate(Jid to, string sid, StanzaNode reason); + public interface Transport : Object { public abstract string transport_ns_uri(); public abstract bool is_transport_available(XmppStream stream, Jid full_jid); @@ -372,9 +392,9 @@ public class Session { // INITIATE_SENT | INITIATE_RECEIVED | CONNECTING TransportParameters? transport = null; - XmppStream hack; + SessionTerminate session_terminate_handler; - public Session.initiate_sent(string sid, Type type, TransportParameters transport, Jid local_full_jid, Jid peer_full_jid, string content_name, XmppStream hack) { + public Session.initiate_sent(string sid, Type type, TransportParameters transport, Jid local_full_jid, Jid peer_full_jid, string content_name, owned SessionTerminate session_terminate_handler) { this.state = State.INITIATE_SENT; this.sid = sid; this.type_ = type; @@ -384,10 +404,10 @@ public class Session { this.content_name = content_name; this.transport = transport; this.connection = new Connection(this); - this.hack = hack; + this.session_terminate_handler = (owned)session_terminate_handler; } - public Session.initiate_received(string sid, Type type, TransportParameters? transport, Jid local_full_jid, Jid peer_full_jid, string content_name, XmppStream hack) { + public Session.initiate_received(string sid, Type type, TransportParameters? transport, Jid local_full_jid, Jid peer_full_jid, string content_name, owned SessionTerminate session_terminate_handler) { this.state = State.INITIATE_RECEIVED; this.sid = sid; this.type_ = type; @@ -397,7 +417,7 @@ public class Session { this.content_name = content_name; this.transport = transport; this.connection = new Connection(this); - this.hack = hack; + this.session_terminate_handler = (owned)session_terminate_handler; } public void handle_iq_set(XmppStream stream, string action, StanzaNode jingle, Iq.Stanza iq) throws IqError { @@ -466,7 +486,7 @@ public class Session { // TODO(hrxi): try negotiating other transports… StanzaNode reason = new StanzaNode.build("reason", NS_URI) .put_node(new StanzaNode.build("failed-transport", NS_URI)); - terminate(stream, reason, "failed transport"); + terminate(reason, "failed transport"); } } void handle_session_terminate(XmppStream stream, StanzaNode jingle, Iq.Stanza iq) throws IqError { @@ -544,7 +564,7 @@ public class Session { } StanzaNode reason = new StanzaNode.build("reason", NS_URI) .put_node(new StanzaNode.build("decline", NS_URI)); - terminate(stream, reason, "declined"); + terminate(reason, "declined"); } public void set_application_error(XmppStream stream, StanzaNode? application_reason = null) { @@ -553,7 +573,7 @@ public class Session { if (application_reason != null) { reason.put_node(application_reason); } - terminate(stream, reason, "application error"); + terminate(reason, "application error"); } public void on_connection_error(IOError error) { @@ -563,15 +583,15 @@ public class Session { .put_node(new StanzaNode.build("text", NS_URI) .put_node(new StanzaNode.text(error.message)) ); - terminate(hack, reason, "transport error: $(error.message)"); + terminate(reason, "transport error: $(error.message)"); } public void on_connection_close() { StanzaNode reason = new StanzaNode.build("reason", NS_URI) .put_node(new StanzaNode.build("success", NS_URI)); - terminate(hack, reason, "success"); + terminate(reason, "success"); } - public void terminate(XmppStream stream, StanzaNode reason, string? local_reason) { + public void terminate(StanzaNode reason, string? local_reason) { if (state == State.ENDED) { return; } @@ -583,18 +603,8 @@ public class Session { } } - StanzaNode jingle = new StanzaNode.build("jingle", NS_URI) - .add_self_xmlns() - .put_attribute("action", "session-terminate") - .put_attribute("sid", sid) - .put_node(reason); - Iq.Stanza iq = new Iq.Stanza.set(jingle) { to=peer_full_jid }; - stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq); - + session_terminate_handler(peer_full_jid, sid, reason); state = State.ENDED; - // Immediately remove the session from the open sessions as per the - // XEP, don't wait for confirmation. - stream.get_flag(Flag.IDENTITY).remove_session(sid); } }