diff options
Diffstat (limited to 'xmpp-vala')
-rw-r--r-- | xmpp-vala/CMakeLists.txt | 1 | ||||
-rw-r--r-- | xmpp-vala/meson.build | 1 | ||||
-rw-r--r-- | xmpp-vala/src/core/direct_tls_xmpp_stream.vala | 2 | ||||
-rw-r--r-- | xmpp-vala/src/core/io_xmpp_stream.vala | 28 | ||||
-rw-r--r-- | xmpp-vala/src/core/stanza_reader.vala | 11 | ||||
-rw-r--r-- | xmpp-vala/src/core/stanza_writer.vala | 18 | ||||
-rw-r--r-- | xmpp-vala/src/core/starttls_xmpp_stream.vala | 2 | ||||
-rw-r--r-- | xmpp-vala/src/core/stream_connect.vala | 8 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0060_pubsub.vala | 59 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0084_user_avatars.vala | 15 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0394_message_markup.vala | 81 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0402_bookmarks2.vala | 2 |
12 files changed, 177 insertions, 51 deletions
diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt index cfbc0aaf..fa0b08ef 100644 --- a/xmpp-vala/CMakeLists.txt +++ b/xmpp-vala/CMakeLists.txt @@ -55,6 +55,7 @@ SOURCES "src/module/xep/0048_bookmarks.vala" "src/module/xep/0048_conference.vala" + "src/module/xep/0394_message_markup.vala" "src/module/xep/0402_bookmarks2.vala" "src/module/xep/0004_data_forms.vala" diff --git a/xmpp-vala/meson.build b/xmpp-vala/meson.build index be5e96a8..7d062db3 100644 --- a/xmpp-vala/meson.build +++ b/xmpp-vala/meson.build @@ -55,6 +55,7 @@ sources = files( 'src/module/xep/0047_in_band_bytestreams.vala', 'src/module/xep/0048_bookmarks.vala', 'src/module/xep/0048_conference.vala', + 'src/module/xep/0394_message_markup.vala', 'src/module/xep/0049_private_xml_storage.vala', 'src/module/xep/0054_vcard/module.vala', 'src/module/xep/0059_result_set_management.vala', diff --git a/xmpp-vala/src/core/direct_tls_xmpp_stream.vala b/xmpp-vala/src/core/direct_tls_xmpp_stream.vala index 26adc90f..f2e06e2c 100644 --- a/xmpp-vala/src/core/direct_tls_xmpp_stream.vala +++ b/xmpp-vala/src/core/direct_tls_xmpp_stream.vala @@ -17,7 +17,7 @@ public class Xmpp.DirectTlsXmppStream : TlsXmppStream { SocketClient client = new SocketClient(); try { debug("Connecting to %s:%i (tls)", host, port); - IOStream? io_stream = yield client.connect_to_host_async(host, port); + IOStream? io_stream = yield client.connect_to_host_async(host, port, cancellable); TlsConnection tls_connection = TlsClientConnection.new(io_stream, new NetworkAddress(remote_name.to_string(), port)); #if GLIB_2_60 tls_connection.set_advertised_protocols(ADVERTISED_PROTOCOLS); diff --git a/xmpp-vala/src/core/io_xmpp_stream.vala b/xmpp-vala/src/core/io_xmpp_stream.vala index 9c58a46b..1d9d061b 100644 --- a/xmpp-vala/src/core/io_xmpp_stream.vala +++ b/xmpp-vala/src/core/io_xmpp_stream.vala @@ -6,32 +6,36 @@ public interface Xmpp.WriteNodeFunc : Object { public abstract class Xmpp.IoXmppStream : XmppStream { private IOStream? stream; + internal Cancellable cancellable; internal StanzaReader? reader; internal StanzaWriter? writer; internal WriteNodeFunc? write_obj = null; - protected IoXmppStream(Jid remote_name) { + protected IoXmppStream(Jid remote_name, Cancellable? cancellable = null) { base(remote_name); + this.cancellable = cancellable ?? new Cancellable(); + } + + public void cancel() { + cancellable.cancel(); } public override async void disconnect() throws IOError { disconnected = true; + cancel(); if (writer == null || reader == null || stream == null) { throw new IOError.CLOSED("trying to disconnect, but no stream open"); } log.str("OUT", "</stream:stream>", this); - yield writer.write("</stream:stream>"); - reader.cancel(); + yield writer.write("</stream:stream>", Priority.LOW, new Cancellable()); yield stream.close_async(); } public void reset_stream(IOStream stream) { this.stream = stream; - reader = new StanzaReader.for_stream(stream.input_stream); - writer = new StanzaWriter.for_stream(stream.output_stream); - - writer.cancel.connect(reader.cancel); + reader = new StanzaReader.for_stream(stream.input_stream, cancellable); + writer = new StanzaWriter.for_stream(stream.output_stream, cancellable); require_setup(); } @@ -48,18 +52,20 @@ public abstract class Xmpp.IoXmppStream : XmppStream { write_async.begin(node, io_priority, null, (obj, res) => { try { write_async.end(res); - } catch (Error e) { } + } catch (Error e) { + warning("Error while writing: %s", e.message); + } }); } public override async void write_async(StanzaNode node, int io_priority = Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { if (write_obj != null) { - yield write_obj.write_stanza(this, node, io_priority, cancellable); + yield write_obj.write_stanza(this, node, io_priority, cancellable ?? this.cancellable); } else { StanzaWriter? writer = this.writer; if (writer == null) throw new IOError.NOT_CONNECTED("trying to write, but no stream open"); log.node("OUT", node, this); - yield ((!)writer).write_node(node, io_priority, cancellable); + yield ((!)writer).write_node(node, io_priority, cancellable ?? this.cancellable); } } @@ -75,7 +81,7 @@ public abstract class Xmpp.IoXmppStream : XmppStream { .put_attribute("stream", "http://etherx.jabber.org/streams", XMLNS_URI); outs.has_nodes = true; log.node("OUT ROOT", outs, this); - write(outs); + yield write_async(outs, Priority.HIGH, cancellable); received_root_node(this, yield read_root()); setup_needed = false; diff --git a/xmpp-vala/src/core/stanza_reader.vala b/xmpp-vala/src/core/stanza_reader.vala index 17f0b7b0..349476ec 100644 --- a/xmpp-vala/src/core/stanza_reader.vala +++ b/xmpp-vala/src/core/stanza_reader.vala @@ -13,7 +13,7 @@ public class StanzaReader { private uint8[] buffer; private int buffer_fill = 0; private int buffer_pos = 0; - private Cancellable cancellable = new Cancellable(); + private Cancellable? cancellable; private NamespaceState ns_state = new NamespaceState(); @@ -26,19 +26,16 @@ public class StanzaReader { this.for_buffer(s.data); } - public StanzaReader.for_stream(InputStream input) { + public StanzaReader.for_stream(InputStream input, Cancellable? cancellable = null) { this.input = input; + this.cancellable = cancellable; buffer = new uint8[BUFFER_MAX]; } - public void cancel() { - cancellable.cancel(); - } - private async void update_buffer() throws IOError { InputStream? input = this.input; if (input == null) throw new IOError.CLOSED("No input stream specified and end of buffer reached."); - if (cancellable.is_cancelled()) throw new IOError.CANCELLED("Input stream is canceled."); + if (cancellable != null && cancellable.is_cancelled()) throw new IOError.CANCELLED("Input stream is canceled."); buffer_fill = (int) yield ((!)input).read_async(buffer, GLib.Priority.DEFAULT, cancellable); if (buffer_fill == 0) throw new IOError.CLOSED("End of input stream reached."); buffer_pos = 0; diff --git a/xmpp-vala/src/core/stanza_writer.vala b/xmpp-vala/src/core/stanza_writer.vala index aecf8983..79af402e 100644 --- a/xmpp-vala/src/core/stanza_writer.vala +++ b/xmpp-vala/src/core/stanza_writer.vala @@ -1,19 +1,19 @@ namespace Xmpp { public class StanzaWriter { - public signal void cancel(); - + private Cancellable? connection_cancellable; private OutputStream output; private Queue<SourceFuncWrapper> queue = new Queue<SourceFuncWrapper>(); private bool running = false; - public StanzaWriter.for_stream(OutputStream output) { + public StanzaWriter.for_stream(OutputStream output, Cancellable? cancellable = null) { this.output = output; + this.connection_cancellable = cancellable; } public async void write_node(StanzaNode node, int io_priority = Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { - yield write_data(node.to_xml().data, io_priority, cancellable); + yield write_data(node.to_xml().data, io_priority, cancellable ?? connection_cancellable); } public async void write_nodes(StanzaNode node1, StanzaNode node2, int io_priority = Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { @@ -29,11 +29,11 @@ public class StanzaWriter { concat[i++] = datum; } - yield write_data(concat, io_priority, cancellable); + yield write_data(concat, io_priority, cancellable ?? connection_cancellable); } public async void write(string s, int io_priority = Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { - yield write_data(s.data, io_priority, cancellable); + yield write_data(s.data, io_priority, cancellable ?? connection_cancellable); } private async void write_data(owned uint8[] data, int io_priority = Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { @@ -45,10 +45,12 @@ public class StanzaWriter { try { yield output.write_all_async(data, io_priority, cancellable, null); } catch (IOError e) { - cancel(); + if (!(e is IOError.CANCELLED)) { + connection_cancellable.cancel(); + } throw e; } catch (GLib.Error e) { - cancel(); + connection_cancellable.cancel(); throw new IOError.FAILED("Error in GLib: %s".printf(e.message)); } finally { SourceFuncWrapper? sfw = queue.pop_head(); diff --git a/xmpp-vala/src/core/starttls_xmpp_stream.vala b/xmpp-vala/src/core/starttls_xmpp_stream.vala index 0d4fbc7d..01c75207 100644 --- a/xmpp-vala/src/core/starttls_xmpp_stream.vala +++ b/xmpp-vala/src/core/starttls_xmpp_stream.vala @@ -17,7 +17,7 @@ public class Xmpp.StartTlsXmppStream : TlsXmppStream { try { SocketClient client = new SocketClient(); debug("Connecting to %s:%i (starttls)", host, port); - IOStream stream = yield client.connect_to_host_async(host, port); + IOStream stream = yield client.connect_to_host_async(host, port, cancellable); reset_stream(stream); yield setup(); diff --git a/xmpp-vala/src/core/stream_connect.vala b/xmpp-vala/src/core/stream_connect.vala index a4c5b82e..17d47f38 100644 --- a/xmpp-vala/src/core/stream_connect.vala +++ b/xmpp-vala/src/core/stream_connect.vala @@ -69,8 +69,16 @@ namespace Xmpp { stream.add_module(module); } + uint connection_timeout_id = Timeout.add_seconds(30, () => { + warning("Connection attempt timed out"); + stream.disconnect(); + return Source.REMOVE; + }); + yield stream.connect(); + Source.remove(connection_timeout_id); + return new XmppStreamResult() { stream=stream }; } catch (IOError e) { warning("Could not establish XMPP session with %s:%i: %s", target.host, target.port, e.message); diff --git a/xmpp-vala/src/module/xep/0060_pubsub.vala b/xmpp-vala/src/module/xep/0060_pubsub.vala index 77f9aee6..c6395eb9 100644 --- a/xmpp-vala/src/module/xep/0060_pubsub.vala +++ b/xmpp-vala/src/module/xep/0060_pubsub.vala @@ -17,11 +17,12 @@ namespace Xmpp.Xep.Pubsub { private HashMap<string, ItemListenerDelegate> item_listeners = new HashMap<string, ItemListenerDelegate>(); private HashMap<string, RetractListenerDelegate> retract_listeners = new HashMap<string, RetractListenerDelegate>(); - private ArrayList<string> pep_subset_listeners = new ArrayList<string>(); + private HashMap<string, DeleteListenerDelegate> delete_listeners = new HashMap<string, DeleteListenerDelegate>(); - public void add_filtered_notification(XmppStream stream, string node, bool pep_subset, + public void add_filtered_notification(XmppStream stream, string node, owned ItemListenerDelegate.ResultFunc? item_listener, - owned RetractListenerDelegate.ResultFunc? retract_listener) { + owned RetractListenerDelegate.ResultFunc? retract_listener, + owned DeleteListenerDelegate.ResultFunc? delete_listener) { stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature_notify(stream, node); if (item_listener != null) { item_listeners[node] = new ItemListenerDelegate((owned)item_listener); @@ -29,8 +30,8 @@ namespace Xmpp.Xep.Pubsub { if (retract_listener != null) { retract_listeners[node] = new RetractListenerDelegate((owned)retract_listener); } - if (pep_subset) { - pep_subset_listeners.add(node); + if (delete_listener != null) { + delete_listeners[node] = new DeleteListenerDelegate((owned)delete_listener); } } @@ -181,30 +182,41 @@ namespace Xmpp.Xep.Pubsub { private void on_received_message(XmppStream stream, MessageStanza message) { StanzaNode event_node = message.stanza.get_subnode("event", NS_URI_EVENT); if (event_node == null) return; - StanzaNode items_node = event_node.get_subnode("items", NS_URI_EVENT); - if (items_node == null) return; - string node = items_node.get_attribute("node", NS_URI_EVENT); - if (!message.from.is_bare() && pep_subset_listeners.contains(node)) { + if (!message.from.is_bare()) { warning("Got a PEP message from a full JID (%s), ignoring.", message.from.to_string()); return; } - StanzaNode? item_node = items_node.get_subnode("item", NS_URI_EVENT); - if (item_node != null) { - string id = item_node.get_attribute("id", NS_URI_EVENT); + StanzaNode items_node = event_node.get_subnode("items", NS_URI_EVENT); + if (items_node != null) { + string node = items_node.get_attribute("node", NS_URI_EVENT); + + StanzaNode? item_node = items_node.get_subnode("item", NS_URI_EVENT); + if (item_node != null) { + string id = item_node.get_attribute("id", NS_URI_EVENT); + + if (item_listeners.has_key(node)) { + item_listeners[node].on_result(stream, message.from, id, item_node.sub_nodes[0]); + } + } + + StanzaNode? retract_node = items_node.get_subnode("retract", NS_URI_EVENT); + if (retract_node != null) { + string id = retract_node.get_attribute("id", NS_URI_EVENT); - if (item_listeners.has_key(node)) { - item_listeners[node].on_result(stream, message.from, id, item_node.sub_nodes[0]); + if (retract_listeners.has_key(node)) { + retract_listeners[node].on_result(stream, message.from, id); + } } } - StanzaNode? retract_node = items_node.get_subnode("retract", NS_URI_EVENT); - if (retract_node != null) { - string id = retract_node.get_attribute("id", NS_URI_EVENT); + StanzaNode? delete_node = event_node.get_subnode("delete", NS_URI_EVENT); + if (delete_node != null) { + string node = delete_node.get_attribute("node", NS_URI_EVENT); - if (retract_listeners.has_key(node)) { - retract_listeners[node].on_result(stream, message.from, id); + if (delete_listeners.has_key(node)) { + delete_listeners[node].on_result(stream, message.from); } } } @@ -264,4 +276,13 @@ namespace Xmpp.Xep.Pubsub { } } + public class DeleteListenerDelegate { + public delegate void ResultFunc(XmppStream stream, Jid jid); + public ResultFunc on_result { get; private owned set; } + + public DeleteListenerDelegate(owned ResultFunc on_result) { + this.on_result = (owned) on_result; + } + } + } diff --git a/xmpp-vala/src/module/xep/0084_user_avatars.vala b/xmpp-vala/src/module/xep/0084_user_avatars.vala index f3cd4060..4d84b34b 100644 --- a/xmpp-vala/src/module/xep/0084_user_avatars.vala +++ b/xmpp-vala/src/module/xep/0084_user_avatars.vala @@ -20,6 +20,11 @@ namespace Xmpp.Xep.UserAvatars { stream.get_module(Pubsub.Module.IDENTITY).publish.begin(stream, null, NS_URI_METADATA, sha1, metadata_node); } + public void unset_avatar(XmppStream stream) { + StanzaNode metadata_node = new StanzaNode.build("metadata", NS_URI_METADATA).add_self_xmlns(); + stream.get_module(Pubsub.Module.IDENTITY).delete_node(stream, null, NS_URI_METADATA); + } + public async Bytes? fetch_image(XmppStream stream, Jid jid, string hash) { Gee.List<StanzaNode>? items = yield stream.get_module(Pubsub.Module.IDENTITY).request_all(stream, jid, NS_URI_DATA); if (items == null || items.size == 0 || items[0].sub_nodes.size == 0) return null; @@ -41,23 +46,27 @@ namespace Xmpp.Xep.UserAvatars { public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0084_user_avatars"); public signal void received_avatar_hash(XmppStream stream, Jid jid, string id); + public signal void avatar_removed(XmppStream stream, Jid jid); public override void attach(XmppStream stream) { - stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NS_URI_METADATA, true, on_pupsub_event, null); + stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NS_URI_METADATA, on_pupsub_item, null, on_pubsub_delete); } public override void detach(XmppStream stream) { stream.get_module(Pubsub.Module.IDENTITY).remove_filtered_notification(stream, NS_URI_METADATA); } - - public void on_pupsub_event(XmppStream stream, Jid jid, string hash, StanzaNode? node) { + public void on_pupsub_item(XmppStream stream, Jid jid, string hash, StanzaNode? node) { StanzaNode? info_node = node.get_subnode("info", NS_URI_METADATA); string? type = info_node == null ? null : info_node.get_attribute("type"); if (type != "image/png" && type != "image/jpeg") return; received_avatar_hash(stream, jid, hash); } + public void on_pubsub_delete(XmppStream stream, Jid jid) { + avatar_removed(stream, jid); + } + public override string get_ns() { return NS_URI; } public override string get_id() { return IDENTITY.id; } } diff --git a/xmpp-vala/src/module/xep/0394_message_markup.vala b/xmpp-vala/src/module/xep/0394_message_markup.vala new file mode 100644 index 00000000..32b441af --- /dev/null +++ b/xmpp-vala/src/module/xep/0394_message_markup.vala @@ -0,0 +1,81 @@ +using Gee; + +namespace Xmpp.Xep.MessageMarkup { + + public const string NS_URI = "urn:xmpp:markup:0"; + + public enum SpanType { + EMPHASIS, + STRONG_EMPHASIS, + DELETED, + } + + public class Span : Object { + public Gee.List<SpanType> types { get; set; } + public int start_char { get; set; } + public int end_char { get; set; } + } + + public Gee.List<Span> get_spans(MessageStanza stanza) { + var ret = new ArrayList<Span>(); + + foreach (StanzaNode span_node in stanza.stanza.get_deep_subnodes(NS_URI + ":markup", NS_URI + ":span")) { + int start_char = span_node.get_attribute_int("start", -1, NS_URI); + int end_char = span_node.get_attribute_int("end", -1, NS_URI); + if (start_char == -1 || end_char == -1) continue; + + var types = new ArrayList<SpanType>(); + foreach (StanzaNode span_subnode in span_node.get_all_subnodes()) { + types.add(str_to_span_type(span_subnode.name)); + } + ret.add(new Span() { types=types, start_char=start_char, end_char=end_char }); + } + return ret; + } + + public void add_spans(MessageStanza stanza, Gee.List<Span> spans) { + if (spans.is_empty) return; + + StanzaNode markup_node = new StanzaNode.build("markup", NS_URI).add_self_xmlns(); + + foreach (var span in spans) { + StanzaNode span_node = new StanzaNode.build("span", NS_URI) + .put_attribute("start", span.start_char.to_string(), NS_URI) + .put_attribute("end", span.end_char.to_string(), NS_URI); + + foreach (var type in span.types) { + span_node.put_node(new StanzaNode.build(span_type_to_str(type), NS_URI)); + } + markup_node.put_node(span_node); + } + + stanza.stanza.put_node(markup_node); + } + + public static string span_type_to_str(Xep.MessageMarkup.SpanType span_type) { + switch (span_type) { + case Xep.MessageMarkup.SpanType.EMPHASIS: + return "emphasis"; + case Xep.MessageMarkup.SpanType.STRONG_EMPHASIS: + return "strong"; + case Xep.MessageMarkup.SpanType.DELETED: + return "deleted"; + default: + return ""; + } + } + + public static Xep.MessageMarkup.SpanType str_to_span_type(string span_str) { + switch (span_str) { + case "emphasis": + return Xep.MessageMarkup.SpanType.EMPHASIS; + case "strong": + return Xep.MessageMarkup.SpanType.STRONG_EMPHASIS; + case "deleted": + return Xep.MessageMarkup.SpanType.DELETED; + default: + return Xep.MessageMarkup.SpanType.EMPHASIS; + } + } + +}
\ No newline at end of file diff --git a/xmpp-vala/src/module/xep/0402_bookmarks2.vala b/xmpp-vala/src/module/xep/0402_bookmarks2.vala index d1e53e6e..429f26f5 100644 --- a/xmpp-vala/src/module/xep/0402_bookmarks2.vala +++ b/xmpp-vala/src/module/xep/0402_bookmarks2.vala @@ -120,7 +120,7 @@ public class Module : BookmarksProvider, XmppStreamModule { } public override void attach(XmppStream stream) { - stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NS_URI, true, on_pupsub_item, on_pupsub_retract); + stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NS_URI, on_pupsub_item, on_pupsub_retract, null); } public override void detach(XmppStream stream) { |