aboutsummaryrefslogtreecommitdiff
path: root/xmpp-vala/src
diff options
context:
space:
mode:
Diffstat (limited to 'xmpp-vala/src')
-rw-r--r--xmpp-vala/src/module/iq/module.vala13
-rw-r--r--xmpp-vala/src/module/stanza_error.vala3
-rw-r--r--xmpp-vala/src/module/xep/0045_muc/module.vala2
-rw-r--r--xmpp-vala/src/module/xep/0082_date_time_profiles.vala33
-rw-r--r--xmpp-vala/src/module/xep/0202_entity_time.vala75
-rw-r--r--xmpp-vala/src/module/xep/0203_delayed_delivery.vala4
-rw-r--r--xmpp-vala/src/module/xep/0215_external_service_discovery.vala2
-rw-r--r--xmpp-vala/src/module/xep/0313_2_message_archive_management.vala4
-rw-r--r--xmpp-vala/src/module/xep/0446_file_metadata_element.vala4
9 files changed, 128 insertions, 12 deletions
diff --git a/xmpp-vala/src/module/iq/module.vala b/xmpp-vala/src/module/iq/module.vala
index 172aa9b1..bb9260c9 100644
--- a/xmpp-vala/src/module/iq/module.vala
+++ b/xmpp-vala/src/module/iq/module.vala
@@ -19,11 +19,20 @@ namespace Xmpp.Iq {
Iq.Stanza? return_stanza = null;
responseListeners[iq.id] = new ResponseListener((_, result_iq) => {
return_stanza = result_iq;
- Idle.add(send_iq_async.callback);
+ if (cancellable == null || !cancellable.is_cancelled()) {
+ Idle.add(send_iq_async.callback);
+ }
});
stream.write_async(iq.stanza, io_priority, cancellable);
+ ulong cancelled_handler_id = 0;
+ if (cancellable != null) {
+ cancelled_handler_id = cancellable.cancelled.connect(() => Idle.add(send_iq_async.callback));
+ }
yield;
- cancellable.set_error_if_cancelled();
+ if (cancellable != null) {
+ cancellable.disconnect(cancelled_handler_id);
+ cancellable.set_error_if_cancelled();
+ }
return return_stanza;
}
diff --git a/xmpp-vala/src/module/stanza_error.vala b/xmpp-vala/src/module/stanza_error.vala
index 5e872291..1a69fd30 100644
--- a/xmpp-vala/src/module/stanza_error.vala
+++ b/xmpp-vala/src/module/stanza_error.vala
@@ -88,6 +88,9 @@ namespace Xmpp {
public ErrorStanza.feature_not_implemented(string? human_readable = null) {
this.build(TYPE_MODIFY, CONDITION_FEATURE_NOT_IMPLEMENTED, human_readable, null);
}
+ public ErrorStanza.forbidden(string? human_readable = null) {
+ this.build(TYPE_AUTH, CONDITION_FORBIDDEN, human_readable, null);
+ }
public ErrorStanza.item_not_found(StanzaNode? application_condition = null) {
this.build(TYPE_CANCEL, CONDITION_ITEM_NOT_FOUND, null, application_condition);
}
diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala
index f660a1cc..88ff819f 100644
--- a/xmpp-vala/src/module/xep/0045_muc/module.vala
+++ b/xmpp-vala/src/module/xep/0045_muc/module.vala
@@ -100,7 +100,7 @@ public class Module : XmppStreamModule {
x_node.put_node(history_node);
if (history_since != null) {
- history_node.set_attribute("since", DateTimeProfiles.to_datetime(history_since));
+ history_node.set_attribute("since", DateTimeProfiles.format_time(history_since));
} else if (!receive_history) {
history_node.set_attribute("maxchars", "0");
}
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 8b40d3ac..3237208e 100644
--- a/xmpp-vala/src/module/xep/0082_date_time_profiles.vala
+++ b/xmpp-vala/src/module/xep/0082_date_time_profiles.vala
@@ -1,11 +1,40 @@
namespace Xmpp.Xep.DateTimeProfiles {
-public DateTime? parse_string(string time_string) {
+public DateTime? parse_time(string time_string) {
return new DateTime.from_iso8601(time_string, null);
}
-public string to_datetime(DateTime time) {
+public TimeZone? parse_tzd(string tzd) {
+ if (tzd == "Z") return new TimeZone.utc();
+ // We support parsing TZD without positive or negative sign prefix for compatibility
+ string unprefixed;
+ if (tzd.length == 5) {
+ unprefixed = tzd;
+ } else if (tzd.length == 6 && (tzd.has_prefix("-") || tzd.has_prefix("+"))) {
+ unprefixed = tzd.substring(1);
+ } else {
+ return null;
+ }
+ int h_offset = unprefixed.substring(0, 2).to_int();
+ int m_offset = unprefixed.substring(3, 2).to_int();
+ int offset = h_offset * 60 * 60 + m_offset * 60;
+ if (tzd.has_prefix("-")) {
+ offset = -offset;
+ }
+ return new TimeZone.offset(offset);
+}
+
+public string format_time(DateTime time) {
return time.to_utc().format_iso8601().to_string();
}
+public string format_tzd(DateTime time) {
+ TimeSpan utc_offset = time.get_utc_offset();
+ if (utc_offset == 0) return "Z";
+ int m_offset = (int) (utc_offset / TimeSpan.MINUTE).abs() % 60;
+ int h_offset = (int) (utc_offset / TimeSpan.HOUR).abs();
+ string prefix = utc_offset < 0 ? "-" : "+";
+ return "%s%02d:%02d".printf(prefix, h_offset, m_offset);
+}
+
}
diff --git a/xmpp-vala/src/module/xep/0202_entity_time.vala b/xmpp-vala/src/module/xep/0202_entity_time.vala
new file mode 100644
index 00000000..9421d921
--- /dev/null
+++ b/xmpp-vala/src/module/xep/0202_entity_time.vala
@@ -0,0 +1,75 @@
+using Gee;
+
+namespace Xmpp.Xep.EntityTime {
+ public const string NS_URI = "urn:xmpp:time";
+
+ public class Module : XmppStreamModule, Iq.Handler {
+ public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0202_entity_time");
+ public bool enabled { get; set; default = false; }
+
+ private HashMap<Jid, Future<DateTime?>> active_time_requests = new HashMap<Jid, Future<DateTime?>>(Jid.hash_func, Jid.equals_func);
+
+ public async DateTime? query_time(XmppStream stream, Jid jid) {
+ if (!enabled) return null;
+
+ var future = active_time_requests[jid];
+ if (future != null) {
+ try {
+ return yield future.wait_async();
+ } catch (FutureError error) {
+ return null;
+ }
+ }
+
+ var promise = new Promise<DateTime?>();
+ active_time_requests[jid] = promise.future;
+
+ DateTime? res = null;
+ try {
+ Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("time", NS_URI).add_self_xmlns()) { to=jid };
+ var cancellable = new Cancellable();
+ var timeout_id = Timeout.add_seconds_once(10, () => cancellable.cancel());
+ Iq.Stanza result = yield stream.get_module(Iq.Module.IDENTITY).send_iq_async(stream, iq, Priority.HIGH, cancellable);
+ Source.remove(timeout_id);
+ StanzaNode time_node = result.stanza.get_subnode("time", NS_URI);
+ if (time_node == null) return null;
+ StanzaNode tzo_node = time_node.get_subnode("tzo", NS_URI);
+ StanzaNode utc_node = time_node.get_subnode("utc", NS_URI);
+ TimeZone? tzo = null;
+ if (utc_node != null) res = DateTimeProfiles.parse_time(utc_node.get_string_content());
+ if (tzo_node != null) tzo = DateTimeProfiles.parse_tzd(tzo_node.get_string_content());
+ if (res != null && tzo != null) res = res.to_timezone(tzo);
+ promise.set_value(res);
+ } catch (IOError e) {
+ debug("Error while fetching time: %s", e.message);
+ }
+ return res;
+ }
+
+ public override void attach(XmppStream stream) {
+ stream.get_module(Iq.Module.IDENTITY).register_for_namespace(NS_URI, this);
+ stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
+ }
+
+ public override void detach(XmppStream stream) {
+ stream.get_module(Iq.Module.IDENTITY).unregister_from_namespace(NS_URI, this);
+ stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
+ }
+
+ public async void on_iq_get(XmppStream stream, Iq.Stanza iq) {
+ var roster_flag = stream.get_flag(Roster.Flag.IDENTITY);
+ if (!enabled || roster_flag == null || roster_flag.get_item(iq.from.bare_jid) == null) {
+ stream.get_module(Iq.Module.IDENTITY).send_iq(stream, new Iq.Stanza.error(iq, new ErrorStanza.forbidden()), null, Priority.LOW);
+ } else {
+ DateTime time = new DateTime.now_local();
+ StanzaNode time_node = new StanzaNode.build("time", NS_URI).add_self_xmlns();
+ time_node.put_node(new StanzaNode.build("utc", NS_URI).put_node(new StanzaNode.text(DateTimeProfiles.format_time(time))));
+ time_node.put_node(new StanzaNode.build("tzo", NS_URI).put_node(new StanzaNode.text(DateTimeProfiles.format_tzd(time))));
+ stream.get_module(Iq.Module.IDENTITY).send_iq(stream, new Iq.Stanza.result(iq, time_node), null, Priority.LOW);
+ }
+ }
+
+ public override string get_ns() { return NS_URI; }
+ public override string get_id() { return IDENTITY.id; }
+ }
+}
diff --git a/xmpp-vala/src/module/xep/0203_delayed_delivery.vala b/xmpp-vala/src/module/xep/0203_delayed_delivery.vala
index ae344d2e..c4be0ad3 100644
--- a/xmpp-vala/src/module/xep/0203_delayed_delivery.vala
+++ b/xmpp-vala/src/module/xep/0203_delayed_delivery.vala
@@ -4,7 +4,7 @@ public const string NS_URI = "urn:xmpp:delay";
public static DateTime? get_time_for_node(StanzaNode node) {
string? time = node.get_attribute("stamp");
- if (time != null) return DateTimeProfiles.parse_string(time);
+ if (time != null) return DateTimeProfiles.parse_time(time);
return null;
}
@@ -24,7 +24,7 @@ public class Module : XmppStreamModule {
public static void set_message_delay(MessageStanza message, DateTime datetime) {
StanzaNode delay_node = (new StanzaNode.build("delay", NS_URI)).add_self_xmlns();
- delay_node.put_attribute("stamp", DateTimeProfiles.to_datetime(datetime));
+ delay_node.put_attribute("stamp", DateTimeProfiles.format_time(datetime));
message.stanza.put_node(delay_node);
}
diff --git a/xmpp-vala/src/module/xep/0215_external_service_discovery.vala b/xmpp-vala/src/module/xep/0215_external_service_discovery.vala
index 6d41a288..5bad71cd 100644
--- a/xmpp-vala/src/module/xep/0215_external_service_discovery.vala
+++ b/xmpp-vala/src/module/xep/0215_external_service_discovery.vala
@@ -26,7 +26,7 @@ namespace Xmpp.Xep.ExternalServiceDiscovery {
service.username = service_node.get_attribute("username", NS_URI);
service.password = service_node.get_attribute("password", NS_URI);
string? expires_str = service_node.get_attribute("expires", NS_URI);
- if (expires_str != null) service.expires = DateTimeProfiles.parse_string(expires_str);
+ if (expires_str != null) service.expires = DateTimeProfiles.parse_time(expires_str);
service.transport = service_node.get_attribute("transport", NS_URI);
service.name = service_node.get_attribute("name", NS_URI);
diff --git a/xmpp-vala/src/module/xep/0313_2_message_archive_management.vala b/xmpp-vala/src/module/xep/0313_2_message_archive_management.vala
index b25f6106..298a1c61 100644
--- a/xmpp-vala/src/module/xep/0313_2_message_archive_management.vala
+++ b/xmpp-vala/src/module/xep/0313_2_message_archive_management.vala
@@ -49,12 +49,12 @@ namespace Xmpp.MessageArchiveManagement.V2 {
}
if (mam_params.start != null) {
DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="start" };
- field.set_value_string(DateTimeProfiles.to_datetime(mam_params.start));
+ field.set_value_string(DateTimeProfiles.format_time(mam_params.start));
fields.add(field);
}
if (mam_params.end != null && mam_params.end_id == null && !mam_params.use_ns2_extended) {
DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="end" };
- field.set_value_string(DateTimeProfiles.to_datetime(mam_params.end));
+ field.set_value_string(DateTimeProfiles.format_time(mam_params.end));
fields.add(field);
}
diff --git a/xmpp-vala/src/module/xep/0446_file_metadata_element.vala b/xmpp-vala/src/module/xep/0446_file_metadata_element.vala
index ebdcbcfa..b4c4367c 100644
--- a/xmpp-vala/src/module/xep/0446_file_metadata_element.vala
+++ b/xmpp-vala/src/module/xep/0446_file_metadata_element.vala
@@ -29,7 +29,7 @@ namespace Xmpp.Xep.FileMetadataElement {
}
if (this.date != null) {
node.put_node(new StanzaNode.build("date", NS_URI).put_node(
- new StanzaNode.text(DateTimeProfiles.to_datetime(this.date))
+ new StanzaNode.text(DateTimeProfiles.format_time(this.date))
));
}
if (this.desc != null) {
@@ -84,7 +84,7 @@ namespace Xmpp.Xep.FileMetadataElement {
}
StanzaNode? date_node = file_node.get_subnode("date");
if (date_node != null && date_node.get_string_content() != null) {
- metadata.date = DateTimeProfiles.parse_string(date_node.get_string_content());
+ metadata.date = DateTimeProfiles.parse_time(date_node.get_string_content());
}
StanzaNode? width_node = file_node.get_subnode("width");
if (width_node != null && width_node.get_string_content() != null) {