diff options
author | fiaxh <git@mx.ax.lt> | 2017-08-16 11:44:42 +0200 |
---|---|---|
committer | fiaxh <git@mx.ax.lt> | 2017-08-17 01:26:03 +0200 |
commit | fb36ea055301b6db513a31acde30f315e2c0fd68 (patch) | |
tree | e9bfeecc12a3824e3b9a86abbed44856ef6dd1e0 /xmpp-vala | |
parent | 30818b3965aef36f161147881967006d6e9376a6 (diff) | |
download | dino-fb36ea055301b6db513a31acde30f315e2c0fd68.tar.gz dino-fb36ea055301b6db513a31acde30f315e2c0fd68.zip |
Message Archive Management
Diffstat (limited to 'xmpp-vala')
-rw-r--r-- | xmpp-vala/CMakeLists.txt | 1 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0004_data_forms.vala | 93 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0045_muc/module.vala | 2 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0082_date_time_profiles.vala | 54 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0203_delayed_delivery.vala | 18 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0313_message_archive_management.vala | 126 |
6 files changed, 228 insertions, 66 deletions
diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt index 4c4f34d2..3306cf7e 100644 --- a/xmpp-vala/CMakeLists.txt +++ b/xmpp-vala/CMakeLists.txt @@ -60,6 +60,7 @@ SOURCES "src/module/xep/0184_message_delivery_receipts.vala" "src/module/xep/0203_delayed_delivery.vala" "src/module/xep/0280_message_carbons.vala" + "src/module/xep/0313_message_archive_management.vala" "src/module/xep/0333_chat_markers.vala" "src/module/xep/0368_srv_records_tls.vala" "src/module/xep/pixbuf_storage.vala" diff --git a/xmpp-vala/src/module/xep/0004_data_forms.vala b/xmpp-vala/src/module/xep/0004_data_forms.vala index a0e8cd43..57ff834a 100644 --- a/xmpp-vala/src/module/xep/0004_data_forms.vala +++ b/xmpp-vala/src/module/xep/0004_data_forms.vala @@ -21,8 +21,12 @@ public class DataForm { } public void submit() { + on_result(stream, get_submit_node()); + } + + public StanzaNode get_submit_node() { stanza_node.set_attribute("type", "submit"); - on_result(stream, stanza_node); + return stanza_node; } public enum Type { @@ -46,19 +50,24 @@ public class DataForm { } } - public abstract class Field { - public string label { + public class Field { + public StanzaNode node { get; set; } + public string? label { get { return node.get_attribute("label", NS_URI); } set { node.set_attribute("label", value); } + default = null; } - public StanzaNode node { get; set; } - public abstract Type type_ { get; internal set; } - public string var { + public virtual Type? type_ { get; internal set; default=null; } + public string? var { get { return node.get_attribute("var", NS_URI); } set { node.set_attribute("var", value); } } - public Field(StanzaNode node) { + public Field() { + this.node = new StanzaNode.build("field", NS_URI); + } + + public Field.from_node(StanzaNode node) { this.node = node; } @@ -103,73 +112,94 @@ public class DataForm { } public class BooleanField : Field { - public override Type type_ { get; internal set; default=Type.BOOLEAN; } public bool value { get { return get_value_string() == "1"; } set { set_value_string(value ? "1" : "0"); } } - public BooleanField(StanzaNode node) { base(node); } + public BooleanField(StanzaNode node) { + base.from_node(node); + type_ = Type.BOOLEAN; + } } public class FixedField : Field { - public override Type type_ { get; internal set; default=Type.FIXED; } public string value { owned get { return get_value_string(); } set { set_value_string(value); } } - public FixedField(StanzaNode node) { base(node); } + public FixedField(StanzaNode node) { + base.from_node(node); + type_ = Type.FIXED; + } } public class HiddenField : Field { - public override Type type_ { get; internal set; default=Type.HIDDEN; } - public HiddenField(StanzaNode node) { base(node); } + public HiddenField() { + base(); + type_ = Type.HIDDEN;; + node.put_attribute("type", "hidden"); + } + public HiddenField.from_node(StanzaNode node) { + base.from_node(node); + type_ = Type.HIDDEN;; + } } public class JidMultiField : Field { public Gee.List<Option> options { owned get { return get_options(); } } - public override Type type_ { get; internal set; default=Type.JID_MULTI; } public Gee.List<string> value { get; set; } - public JidMultiField(StanzaNode node) { base(node); } + public JidMultiField(StanzaNode node) { + base.from_node(node); + type_ = Type.JID_MULTI; + } } public class ListSingleField : Field { public Gee.List<Option> options { owned get { return get_options(); } } - public override Type type_ { get; internal set; default=Type.LIST_SINGLE; } public string value { owned get { return get_value_string(); } set { set_value_string(value); } } - public ListSingleField(StanzaNode node) { base(node); } + public ListSingleField(StanzaNode node) { + base.from_node(node); + type_ = Type.LIST_SINGLE;; + } } public class ListMultiField : Field { public Gee.List<Option> options { owned get { return get_options(); } } - public override Type type_ { get; internal set; default=Type.LIST_MULTI; } public Gee.List<string> value { get; set; } - public ListMultiField(StanzaNode node) { base(node); } + public ListMultiField(StanzaNode node) { + base.from_node(node); + type_ = Type.LIST_MULTI; + } } public class TextPrivateField : Field { - public override Type type_ { get; internal set; default=Type.TEXT_PRIVATE; } public string value { owned get { return get_value_string(); } set { set_value_string(value); } } - public TextPrivateField(StanzaNode node) { base(node); } + public TextPrivateField(StanzaNode node) { + base.from_node(node); + type_ = Type.TEXT_PRIVATE; + } } public class TextSingleField : Field { - public override Type type_ { get; internal set; default=Type.TEXT_SINGLE; } public string value { owned get { return get_value_string(); } set { set_value_string(value); } } - public TextSingleField(StanzaNode node) { base(node); } + public TextSingleField(StanzaNode node) { + base.from_node(node); + type_ = Type.TEXT_SINGLE; + } } // TODO text-multi - internal DataForm(StanzaNode node, XmppStream stream, owned OnResult listener) { + internal DataForm.from_node(StanzaNode node, XmppStream stream, owned OnResult listener) { this.stanza_node = node; this.stream = stream; this.on_result = (owned)listener; @@ -183,7 +213,7 @@ public class DataForm { case "fixed": fields.add(new FixedField(field_node)); break; case "hidden": - fields.add(new HiddenField(field_node)); break; + fields.add(new HiddenField.from_node(field_node)); break; case "jid-multi": fields.add(new JidMultiField(field_node)); break; case "list-single": @@ -198,9 +228,18 @@ public class DataForm { } } + internal DataForm() { + this.stanza_node = new StanzaNode.build("x", NS_URI).add_self_xmlns(); + } + public delegate void OnResult(XmppStream stream, StanzaNode node); - public static DataForm? create(XmppStream stream, StanzaNode node, owned OnResult listener) { - return new DataForm(node, stream, (owned)listener); + public static DataForm? create_from_node(XmppStream stream, StanzaNode node, owned OnResult listener) { + return new DataForm.from_node(node, stream, (owned)listener); + } + + public void add_field(Field field) { + fields.add(field); + stanza_node.put_node(field.node); } } diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala index a5d99b2c..fd4e8ba5 100644 --- a/xmpp-vala/src/module/xep/0045_muc/module.vala +++ b/xmpp-vala/src/module/xep/0045_muc/module.vala @@ -148,7 +148,7 @@ public class Module : XmppStreamModule { stream.get_module(Iq.Module.IDENTITY).send_iq(stream, get_iq, (stream, form_iq) => { StanzaNode? x_node = form_iq.stanza.get_deep_subnode(NS_URI_OWNER + ":query", DataForms.NS_URI + ":x"); if (x_node != null) { - DataForms.DataForm data_form = DataForms.DataForm.create(stream, x_node, (stream, node) => { + DataForms.DataForm data_form = DataForms.DataForm.create_from_node(stream, x_node, (stream, node) => { StanzaNode stanza_node = new StanzaNode.build("query", NS_URI_OWNER); stanza_node.add_self_xmlns().put_node(node); Iq.Stanza set_iq = new Iq.Stanza.set(stanza_node); diff --git a/xmpp-vala/src/module/xep/0082_date_time_profiles.vala b/xmpp-vala/src/module/xep/0082_date_time_profiles.vala index 57c7ec4d..5c09e4a6 100644 --- a/xmpp-vala/src/module/xep/0082_date_time_profiles.vala +++ b/xmpp-vala/src/module/xep/0082_date_time_profiles.vala @@ -1,42 +1,34 @@ namespace Xmpp.Xep.DateTimeProfiles { -public class Module { - public Regex DATETIME_REGEX; - - public Module() { - DATETIME_REGEX = new Regex("""^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.(\d{3}))?(Z|((\+|\-)(\d{2})(:(\d{2}))?))$"""); - } - - public DateTime? parse_string(string time_string) { - MatchInfo match_info; - if (DATETIME_REGEX.match(time_string, RegexMatchFlags.ANCHORED, out match_info)) { - int year = int.parse(match_info.fetch(1)); - int month = int.parse(match_info.fetch(2)); - int day = int.parse(match_info.fetch(3)); - int hour = int.parse(match_info.fetch(4)); - int minute = int.parse(match_info.fetch(5)); - int second = int.parse(match_info.fetch(6)); - DateTime datetime = new DateTime.utc(year, month, day, hour, minute, second); - if (match_info.fetch(9) != "Z") { - char plusminus = match_info.fetch(11)[0]; - int tz_hour = int.parse(match_info.fetch(12)); - int tz_minute = int.parse(match_info.fetch(13)); - if (plusminus == '-') { - tz_hour *= -1; - tz_minute *= -1; - } - datetime.add_hours(tz_hour); - datetime.add_minutes(tz_minute); +public DateTime? parse_string(string time_string) { + Regex DATETIME_REGEX = new Regex("""^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.(\d{3}))?(Z|((\+|\-)(\d{2})(:(\d{2}))?))$"""); + MatchInfo match_info; + if (DATETIME_REGEX.match(time_string, RegexMatchFlags.ANCHORED, out match_info)) { + int year = int.parse(match_info.fetch(1)); + int month = int.parse(match_info.fetch(2)); + int day = int.parse(match_info.fetch(3)); + int hour = int.parse(match_info.fetch(4)); + int minute = int.parse(match_info.fetch(5)); + int second = int.parse(match_info.fetch(6)); + DateTime datetime = new DateTime.utc(year, month, day, hour, minute, second); + if (match_info.fetch(9) != "Z") { + char plusminus = match_info.fetch(11)[0]; + int tz_hour = int.parse(match_info.fetch(12)); + int tz_minute = int.parse(match_info.fetch(13)); + if (plusminus == '-') { + tz_hour *= -1; + tz_minute *= -1; } - return datetime; + datetime.add_hours(tz_hour); + datetime.add_minutes(tz_minute); } - return null; + return datetime; } + return null; +} public string to_datetime(DateTime time) { return time.to_utc().format("%Y-%m-%dT%H:%M:%SZ"); } } - -} diff --git a/xmpp-vala/src/module/xep/0203_delayed_delivery.vala b/xmpp-vala/src/module/xep/0203_delayed_delivery.vala index d2d94367..8ca300c9 100644 --- a/xmpp-vala/src/module/xep/0203_delayed_delivery.vala +++ b/xmpp-vala/src/module/xep/0203_delayed_delivery.vala @@ -8,18 +8,22 @@ namespace Xmpp.Xep.DelayedDelivery { public static void set_message_delay(Message.Stanza message, DateTime datetime) { StanzaNode delay_node = (new StanzaNode.build("delay", NS_URI)).add_self_xmlns(); - delay_node.put_attribute("stamp", (new DateTimeProfiles.Module()).to_datetime(datetime)); + delay_node.put_attribute("stamp", DateTimeProfiles.to_datetime(datetime)); message.stanza.put_node(delay_node); } - public static DateTime? get_send_time(Message.Stanza message) { + public static DateTime? get_time_for_message(Message.Stanza message) { StanzaNode? delay_node = message.stanza.get_subnode("delay", NS_URI); if (delay_node != null) { - string time = delay_node.get_attribute("stamp"); - return (new DateTimeProfiles.Module()).parse_string(time); - } else { - return null; + return get_time_for_node(delay_node); } + return null; + } + + public static DateTime? get_time_for_node(StanzaNode node) { + string? time = node.get_attribute("stamp"); + if (time != null) return DateTimeProfiles.parse_string(time); + return null; } public override void attach(XmppStream stream) { @@ -32,7 +36,7 @@ namespace Xmpp.Xep.DelayedDelivery { public override string get_id() { return IDENTITY.id; } private void on_pre_received_message(XmppStream stream, Message.Stanza message) { - DateTime? datetime = get_send_time(message); + DateTime? datetime = get_time_for_message(message); if (datetime != null) message.add_flag(new MessageFlag(datetime)); } } diff --git a/xmpp-vala/src/module/xep/0313_message_archive_management.vala b/xmpp-vala/src/module/xep/0313_message_archive_management.vala new file mode 100644 index 00000000..522f6dca --- /dev/null +++ b/xmpp-vala/src/module/xep/0313_message_archive_management.vala @@ -0,0 +1,126 @@ +using Xmpp.Core; + +namespace Xmpp.Xep.MessageArchiveManagement { + +public const string NS_URI = "urn:xmpp:mam:2"; +public const string NS_URI_1 = "urn:xmpp:mam:1"; + +public class Module : XmppStreamModule { + public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0313_message_archive_management"); + + public signal void feature_available(XmppStream stream); + + public void query_archive(XmppStream stream, string? jid, DateTime? start, DateTime? end) { + if (stream.get_flag(Flag.IDENTITY) == null) return; + + DataForms.DataForm data_form = new DataForms.DataForm(); + DataForms.DataForm.HiddenField form_type_field = new DataForms.DataForm.HiddenField() { var="FORM_TYPE" }; + form_type_field.set_value_string(NS_VER(stream)); + data_form.add_field(form_type_field); + if (jid != null) { + DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="with" }; + field.set_value_string(jid); + data_form.add_field(field); + } + if (start != null) { + DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="start" }; + field.set_value_string(DateTimeProfiles.to_datetime(start)); + data_form.add_field(field); + } + if (end != null) { + DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="end" }; + field.set_value_string(DateTimeProfiles.to_datetime(end)); + data_form.add_field(field); + } + StanzaNode query_node = new StanzaNode.build("query", NS_VER(stream)).add_self_xmlns().put_node(data_form.get_submit_node()); + Iq.Stanza iq = new Iq.Stanza.set(query_node); + stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, page_through_results); + } + + public override void attach(XmppStream stream) { + stream.get_module(Message.Module.IDENTITY).pre_received_message.connect(on_pre_received_message); + stream.stream_negotiated.connect(query_availability); + } + + public override void detach(XmppStream stream) { } + + public override string get_ns() { return NS_URI; } + public override string get_id() { return IDENTITY.id; } + + private void on_pre_received_message(XmppStream stream, Message.Stanza message) { +// if (message.from != stream.remote_name) return; + if (stream.get_flag(Flag.IDENTITY) == null) return; + + StanzaNode? message_node = message.stanza.get_deep_subnode(NS_VER(stream) + ":result", "urn:xmpp:forward:0:forwarded", Message.NS_URI + ":message"); + if (message_node != null) { + StanzaNode? forward_node = message.stanza.get_deep_subnode(NS_VER(stream) + ":result", "urn:xmpp:forward:0:forwarded", DelayedDelivery.NS_URI + ":delay"); + DateTime? datetime = DelayedDelivery.Module.get_time_for_node(forward_node); + message.add_flag(new MessageFlag(datetime)); + + message.stanza = message_node; + message.rerun_parsing = true; + } + } + + private static void page_through_results(XmppStream stream, Iq.Stanza iq) { + string? last = iq.stanza.get_deep_string_content(NS_VER(stream) + ":fin", "http://jabber.org/protocol/rsm" + ":set", "last"); + if (last == null) { + stream.get_flag(Flag.IDENTITY).cought_up = true; + return; + } + + Iq.Stanza paging_iq = new Iq.Stanza.set( + new StanzaNode.build("query", NS_VER(stream)).add_self_xmlns().put_node( + new StanzaNode.build("set", "http://jabber.org/protocol/rsm").add_self_xmlns().put_node( + new StanzaNode.build("after", "http://jabber.org/protocol/rsm").put_node(new StanzaNode.text(last)) + ) + ) + ); + stream.get_module(Iq.Module.IDENTITY).send_iq(stream, paging_iq, page_through_results); + } + + private void query_availability(XmppStream stream) { + stream.get_module(Xep.ServiceDiscovery.Module.IDENTITY).request_info(stream, get_bare_jid(stream.get_flag(Bind.Flag.IDENTITY).my_jid), (stream, info_result) => { + if (info_result.features.contains(NS_URI)) { + stream.add_flag(new Flag(NS_URI)); + } else if (info_result.features.contains(NS_URI_1)) { + stream.add_flag(new Flag(NS_URI_1)); + } + if (stream.get_flag(Flag.IDENTITY) != null) feature_available(stream); + }); + } + + private static string NS_VER(XmppStream stream) { + return stream.get_flag(Flag.IDENTITY).ns_ver; + } +} + +public class Flag : XmppStreamFlag { + public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "message_archive_management"); + public bool cought_up { get; set; default=false; } + public string ns_ver; + + public Flag(string ns_ver) { + this.ns_ver = ns_ver; + } + + public override string get_ns() { return NS_URI; } + public override string get_id() { return IDENTITY.id; } +} + +public class MessageFlag : Message.MessageFlag { + public const string ID = "message_archive_management"; + + public DateTime? server_time { get; private set; } + + public MessageFlag(DateTime? server_time) { + this.server_time = server_time; + } + + public static MessageFlag? get_flag(Message.Stanza message) { return (MessageFlag) message.get_flag(NS_URI, ID); } + + public override string get_ns() { return NS_URI; } + public override string get_id() { return ID; } +} + +} |