diff options
Diffstat (limited to 'xmpp-vala/src/module/xep')
-rw-r--r-- | xmpp-vala/src/module/xep/0082_date_time_profiles.vala | 21 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0198_stream_management.vala | 112 |
2 files changed, 123 insertions, 10 deletions
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 b2ce1077..57c7ec4d 100644 --- a/xmpp-vala/src/module/xep/0082_date_time_profiles.vala +++ b/xmpp-vala/src/module/xep/0082_date_time_profiles.vala @@ -1,13 +1,13 @@ namespace Xmpp.Xep.DateTimeProfiles { - public class Module { - public Regex DATETIME_REGEX; +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 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) { + 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)); @@ -33,9 +33,10 @@ namespace Xmpp.Xep.DateTimeProfiles { return null; } - public string to_datetime(DateTime time) { - return time.format("%Y-%m-%dT%H:%M:%SZ"); - } +public string to_datetime(DateTime time) { + return time.to_utc().format("%Y-%m-%dT%H:%M:%SZ"); } -}
\ No newline at end of file +} + +} diff --git a/xmpp-vala/src/module/xep/0198_stream_management.vala b/xmpp-vala/src/module/xep/0198_stream_management.vala new file mode 100644 index 00000000..03be907c --- /dev/null +++ b/xmpp-vala/src/module/xep/0198_stream_management.vala @@ -0,0 +1,112 @@ +using Xmpp.Core; + +namespace Xmpp.Xep.StreamManagement { + +public const string NS_URI = "urn:xmpp:sm:3"; + +public class Module : XmppStreamNegotiationModule { + public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0313_message_archive_management"); + + public int h_inbound { get; private set; default=0; } + public string? session_id { get; set; default=null; } + public Gee.List<XmppStreamFlag> flags = null; + + public override void attach(XmppStream stream) { + stream.get_module(Bind.Module.IDENTITY).bound_to_resource.connect(check_enable); + stream.received_features_node.connect(check_resume); + + stream.received_nonza.connect(on_received_nonza); + stream.received_message_stanza.connect(on_stanza_received); + stream.received_presence_stanza.connect(on_stanza_received); + stream.received_iq_stanza.connect(on_stanza_received); + } + + public override void detach(XmppStream stream) { } + + public static void require(XmppStream stream) { + if (stream.get_module(IDENTITY) == null) stream.add_module(new PrivateXmlStorage.Module()); + } + + public override bool mandatory_outstanding(XmppStream stream) { return false; } + + public override bool negotiation_active(XmppStream stream) { + return stream.has_flag(Flag.IDENTITY) && !stream.get_flag(Flag.IDENTITY).finished; + } + + public override string get_ns() { return NS_URI; } + public override string get_id() { return IDENTITY.id; } + + private void on_stanza_received(XmppStream stream, StanzaNode node) { + lock (h_inbound) h_inbound++; + } + + private void check_resume(XmppStream stream) { + if (stream_has_sm_feature(stream) && session_id != null) { + Tls.Flag? tls_flag = stream.get_flag(Tls.Flag.IDENTITY); + if (tls_flag != null && tls_flag.finished) { + StanzaNode node = new StanzaNode.build("resume", NS_URI).add_self_xmlns() + .put_attribute("h", h_inbound.to_string()) + .put_attribute("previd", session_id); + stream.write(node); + stream.add_flag(new Flag()); + } + } + } + + private void check_enable(XmppStream stream) { + if (stream_has_sm_feature(stream) && session_id == null) { + StanzaNode node = new StanzaNode.build("enable", NS_URI).add_self_xmlns().put_attribute("resume", "true"); + stream.write(node); + stream.add_flag(new Flag()); + } + } + + private void on_received_nonza(XmppStream stream, StanzaNode node) { + if (node.ns_uri == NS_URI) { + if (node.name == "r") { + send_ack(stream); + } else if (node.name == "a") { + handle_ack(stream, node); + } else if (node.name in new string[]{"enabled", "resumed", "failed"}) { + stream.get_flag(Flag.IDENTITY).finished = true; + + if (node.name == "enabled") { + lock(h_inbound) h_inbound = 0; + session_id = node.get_attribute("id", NS_URI); + flags = stream.flags; + } else if (node.name == "resumed") { + foreach (XmppStreamFlag flag in flags) { + stream.add_flag(flag); + } + stream.negotiation_complete = true; + } else if (node.name == "failed") { + stream.received_features_node(stream); + session_id = null; + } + } + } + } + + private void send_ack(XmppStream stream) { + StanzaNode node = new StanzaNode.build("a", NS_URI).add_self_xmlns().put_attribute("h", h_inbound.to_string()); + stream.write(node); + } + + private void handle_ack(XmppStream stream, StanzaNode node) { + + } + + private bool stream_has_sm_feature(XmppStream stream) { + return stream.features.get_subnode("sm", NS_URI) != null; + } +} + +public class Flag : XmppStreamFlag { + public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "stream_management"); + public bool finished = false; + + public override string get_ns() { return NS_URI; } + public override string get_id() { return IDENTITY.id; } +} + +} |