aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dino.doap8
-rw-r--r--dino.doap.in8
-rw-r--r--libdino/src/application.vala2
-rw-r--r--libdino/src/entity/settings.vala13
-rw-r--r--libdino/src/service/entity_info.vala63
-rw-r--r--libdino/src/service/module_manager.vala1
-rw-r--r--main/data/chat_input.ui21
-rw-r--r--main/data/gresource.xml1
-rw-r--r--main/data/icons/scalable/status/dino-clock-alt-symbolic.svg2
-rw-r--r--main/data/preferences_window/general_preferences_page.ui7
-rw-r--r--main/data/style.css9
-rw-r--r--main/src/ui/chat_input/view.vala97
-rw-r--r--main/src/ui/conversation_details.vala66
-rw-r--r--main/src/ui/util/preference_group.vala65
-rw-r--r--main/src/view_model/conversation_details.vala1
-rw-r--r--main/src/view_model/preferences_dialog.vala1
-rw-r--r--main/src/view_model/preferences_row.vala1
-rw-r--r--main/src/windows/preferences_window/general_preferences_page.vala3
-rw-r--r--xmpp-vala/meson.build1
-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
28 files changed, 444 insertions, 66 deletions
diff --git a/dino.doap b/dino.doap
index 0b9091ef..96e6913a 100644
--- a/dino.doap
+++ b/dino.doap
@@ -421,6 +421,14 @@
</implements>
<implements>
<xmpp:SupportedXep>
+ <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0202.html"/>
+ <xmpp:version>2.0</xmpp:version>
+ <xmpp:status>complete</xmpp:status>
+ <xmpp:since>0.6</xmpp:since>
+ </xmpp:SupportedXep>
+ </implements>
+ <implements>
+ <xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0203.html"/>
<xmpp:status>complete</xmpp:status>
<xmpp:since>0.1</xmpp:since>
diff --git a/dino.doap.in b/dino.doap.in
index d58541f7..99e3565d 100644
--- a/dino.doap.in
+++ b/dino.doap.in
@@ -241,6 +241,14 @@
</implements>
<implements>
<xmpp:SupportedXep>
+ <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0202.html"/>
+ <xmpp:version>2.0</xmpp:version>
+ <xmpp:status>complete</xmpp:status>
+ <xmpp:since>0.6</xmpp:since>
+ </xmpp:SupportedXep>
+ </implements>
+ <implements>
+ <xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0203.html" />
<xmpp:status>complete</xmpp:status>
<xmpp:since>0.1</xmpp:since>
diff --git a/libdino/src/application.vala b/libdino/src/application.vala
index 737c76c2..ef2d883e 100644
--- a/libdino/src/application.vala
+++ b/libdino/src/application.vala
@@ -52,7 +52,7 @@ public interface Application : GLib.Application {
NotificationEvents.start(stream_interactor);
SearchProcessor.start(stream_interactor, db);
Register.start(stream_interactor, db);
- EntityInfo.start(stream_interactor, db);
+ EntityInfo.start(stream_interactor, db, settings);
MessageCorrection.start(stream_interactor, db);
FileTransferStorage.start(stream_interactor, db);
Reactions.start(stream_interactor, db);
diff --git a/libdino/src/entity/settings.vala b/libdino/src/entity/settings.vala
index 14ac106e..c71a8e57 100644
--- a/libdino/src/entity/settings.vala
+++ b/libdino/src/entity/settings.vala
@@ -9,6 +9,7 @@ public class Settings : Object {
send_typing_ = col_to_bool_or_default("send_typing", true);
send_marker_ = col_to_bool_or_default("send_marker", true);
+ share_time_ = col_to_bool_or_default("share_time", true);
notifications_ = col_to_bool_or_default("notifications", true);
convert_utf8_smileys_ = col_to_bool_or_default("convert_utf8_smileys", true);
check_spelling = col_to_bool_or_default("check_spelling", true);
@@ -43,6 +44,18 @@ public class Settings : Object {
}
}
+ private bool share_time_;
+ public bool share_time {
+ get { return share_time_; }
+ set {
+ db.settings.upsert()
+ .value(db.settings.key, "share_time", true)
+ .value(db.settings.value, value.to_string())
+ .perform();
+ share_time_ = value;
+ }
+ }
+
private bool notifications_;
public bool notifications {
get { return notifications_; }
diff --git a/libdino/src/service/entity_info.vala b/libdino/src/service/entity_info.vala
index 83e27d4b..53d14b15 100644
--- a/libdino/src/service/entity_info.vala
+++ b/libdino/src/service/entity_info.vala
@@ -13,23 +13,35 @@ public class EntityInfo : StreamInteractionModule, Object {
private StreamInteractor stream_interactor;
private Database db;
private EntityCapabilitiesStorage entity_capabilities_storage;
-
+ private Dino.Entities.Settings settings;
private HashMap<Jid, string> entity_caps_hashes = new HashMap<Jid, string>(Jid.hash_func, Jid.equals_func);
private HashMap<string, Gee.List<string>> entity_features = new HashMap<string, Gee.List<string>>();
private HashMap<Jid, Gee.List<string>> jid_features = new HashMap<Jid, Gee.List<string>>(Jid.hash_func, Jid.equals_func);
private HashMap<string, Gee.Set<Identity>> entity_identity = new HashMap<string, Gee.Set<Identity>>();
private HashMap<Jid, Gee.Set<Identity>> jid_identity = new HashMap<Jid, Gee.Set<Identity>>(Jid.hash_func, Jid.equals_func);
+ private HashMap<Jid, int> jid_utc_offset_minutes = new HashMap<Jid, int>(Jid.hash_func, Jid.equals_func);
+ private HashMap<Jid, int> jid_utc_offset_cache_timeout = new HashMap<Jid, int>(Jid.hash_func, Jid.equals_func);
- public static void start(StreamInteractor stream_interactor, Database db) {
- EntityInfo m = new EntityInfo(stream_interactor, db);
+ public static void start(StreamInteractor stream_interactor, Database db, Dino.Entities.Settings settings) {
+ EntityInfo m = new EntityInfo(stream_interactor, db, settings);
stream_interactor.add_module(m);
+ WeakRef m_weak = WeakRef(m);
+ ulong handler_id = settings.notify["share-time"].connect(() => {
+ EntityInfo? entity_info = m_weak.get() as EntityInfo;
+ if (entity_info != null) {
+ entity_info.jid_utc_offset_minutes.clear();
+ entity_info.jid_utc_offset_cache_timeout.clear();
+ }
+ });
+ m.weak_ref(() => settings.disconnect(handler_id));
}
- private EntityInfo(StreamInteractor stream_interactor, Database db) {
+ private EntityInfo(StreamInteractor stream_interactor, Database db, Dino.Entities.Settings settings) {
this.stream_interactor = stream_interactor;
this.db = db;
this.entity_capabilities_storage = new EntityCapabilitiesStorage(db);
+ this.settings = settings;
stream_interactor.account_added.connect(on_account_added);
stream_interactor.connection_manager.stream_opened.connect((account, stream) => {
@@ -78,6 +90,45 @@ public class EntityInfo : StreamInteractionModule, Object {
return null;
}
+ public async int get_utc_offset_minutes_for_full_jid(Account account, Jid full_jid) {
+ if (!settings.share_time) return int.MIN;
+ if (!yield has_feature(account, full_jid, EntityTime.NS_URI)) return int.MIN;
+ int monotonic_time_minutes = (int) (get_monotonic_time() / 1000000l);
+ if (jid_utc_offset_minutes.has_key(full_jid)) {
+ if (jid_utc_offset_cache_timeout[full_jid] > monotonic_time_minutes) {
+ return jid_utc_offset_minutes.get(full_jid);
+ } else {
+ jid_utc_offset_minutes.unset(full_jid);
+ jid_utc_offset_cache_timeout.unset(full_jid);
+ }
+ }
+ XmppStream? stream = stream_interactor.get_stream(account);
+ if (stream == null) return int.MIN;
+ DateTime? time = yield stream.get_module(EntityTime.Module.IDENTITY).query_time(stream, full_jid);
+ int utc_offset = time == null ? int.MIN : (int) (time.get_utc_offset() / TimeSpan.MINUTE);
+ jid_utc_offset_minutes.set(full_jid, utc_offset);
+ jid_utc_offset_cache_timeout.set(full_jid, monotonic_time_minutes + 3 * 60 * 60);
+ return utc_offset;
+ }
+
+ public async int get_utc_offset_minutes_for_bare_jid(Account account, Jid bare_jid) {
+ if (stream_interactor.get_module(RosterManager.IDENTITY).get_roster_item(account, bare_jid) == null) return int.MIN;
+ int utc_offset_minutes = int.MIN;
+ Gee.List<Jid>? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(bare_jid, account);
+ if (full_jids != null) {
+ foreach (Jid full_jid in full_jids) {
+ int jid_utc_offset_minutes = yield get_utc_offset_minutes_for_full_jid(account, full_jid);
+ if (utc_offset_minutes == int.MIN) {
+ utc_offset_minutes = jid_utc_offset_minutes;
+ } else if (jid_utc_offset_minutes != int.MIN && utc_offset_minutes != jid_utc_offset_minutes) {
+ // Return early, time zones don't match
+ return int.MIN;
+ }
+ }
+ }
+ return utc_offset_minutes;
+ }
+
public async bool has_feature(Account account, Jid jid, string feature) {
int has_feature_cached = has_feature_cached_int(account, jid, feature);
if (has_feature_cached != -1) {
@@ -248,6 +299,10 @@ public class EntityInfo : StreamInteractionModule, Object {
private void initialize_modules(Account account, ArrayList<XmppStreamModule> modules) {
modules.add(new Xep.EntityCapabilities.Module(entity_capabilities_storage));
+ var entity_time_module = modules.first_match((it) => it is EntityTime.Module) as EntityTime.Module;
+ if (entity_time_module != null) {
+ settings.bind_property("share-time", entity_time_module, "enabled", BindingFlags.SYNC_CREATE);
+ }
}
}
diff --git a/libdino/src/service/module_manager.vala b/libdino/src/service/module_manager.vala
index ef6ecc00..64be76e1 100644
--- a/libdino/src/service/module_manager.vala
+++ b/libdino/src/service/module_manager.vala
@@ -67,6 +67,7 @@ public class ModuleManager {
module_map[account].add(new Xep.ChatStateNotifications.Module());
module_map[account].add(new Xep.ChatMarkers.Module());
module_map[account].add(new Xep.Ping.Module());
+ module_map[account].add(new Xep.EntityTime.Module());
module_map[account].add(new Xep.DelayedDelivery.Module());
module_map[account].add(new StreamError.Module());
module_map[account].add(new Xep.InBandRegistration.Module());
diff --git a/main/data/chat_input.ui b/main/data/chat_input.ui
index 87b18946..d0d99729 100644
--- a/main/data/chat_input.ui
+++ b/main/data/chat_input.ui
@@ -6,6 +6,27 @@
<property name="orientation">vertical</property>
<property name="margin-top">4</property>
<child>
+ <object class="GtkBox" id="unavailable_box">
+ <property name="margin_start">14</property>
+ <property name="margin_end">14</property>
+ <property name="visible">False</property>
+ <style>
+ <class name="time-offset" />
+ </style>
+ <child>
+ <object class="GtkImage" id="unavailable_icon">
+ <property name="icon-name">dino-clock-alt-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="unavailable_label">
+ <property name="margin_start">8</property>
+ <property name="ellipsize">end</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
<object class="GtkBox" id="outer_box">
<property name="margin_start">14</property>
<property name="margin_end">14</property>
diff --git a/main/data/gresource.xml b/main/data/gresource.xml
index 85449045..db9e5caf 100644
--- a/main/data/gresource.xml
+++ b/main/data/gresource.xml
@@ -67,6 +67,7 @@
<file>icons/scalable/status/dino-changes-allow-symbolic.svg</file>
<file>icons/scalable/status/dino-changes-prevent-symbolic.svg</file>
<file>icons/scalable/status/dino-channel-insecure-symbolic.svg</file>
+ <file>icons/scalable/status/dino-clock-alt-symbolic.svg</file>
<file>icons/scalable/status/dino-dialog-warning-symbolic.svg</file>
<file>icons/scalable/status/dino-double-tick-symbolic.svg</file>
<file>icons/scalable/status/dino-face-uncertain-symbolic.svg</file>
diff --git a/main/data/icons/scalable/status/dino-clock-alt-symbolic.svg b/main/data/icons/scalable/status/dino-clock-alt-symbolic.svg
new file mode 100644
index 00000000..1fdd96ce
--- /dev/null
+++ b/main/data/icons/scalable/status/dino-clock-alt-symbolic.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><g fill="#222222"><path d="m 8 0 c -4.40625 0 -8 3.59375 -8 8 s 3.59375 8 8 8 s 8 -3.59375 8 -8 s -3.59375 -8 -8 -8 z m 0 2 c 3.324219 0 6 2.675781 6 6 s -2.675781 6 -6 6 s -6 -2.675781 -6 -6 s 2.675781 -6 6 -6 z m 0 0"/><path d="m 4.929688 4.953125 c -0.132813 0.003906 -0.257813 0.058594 -0.351563 0.152344 c -0.191406 0.195312 -0.1875 0.511719 0.007813 0.707031 l 3.113281 3.042969 c 0.105469 0.097656 0.246093 0.144531 0.386719 0.128906 h 2.914062 c 0.277344 0 0.5 -0.222656 0.5 -0.5 c 0 -0.273437 -0.222656 -0.5 -0.5 -0.5 h -2.761719 l -2.953125 -2.886719 c -0.09375 -0.09375 -0.222656 -0.144531 -0.355468 -0.144531 z m 0 0"/></g></svg>
diff --git a/main/data/preferences_window/general_preferences_page.ui b/main/data/preferences_window/general_preferences_page.ui
index 9e76e17a..ca240511 100644
--- a/main/data/preferences_window/general_preferences_page.ui
+++ b/main/data/preferences_window/general_preferences_page.ui
@@ -16,6 +16,13 @@
<property name="use-underline">True</property>
</object>
</child>
+ <child>
+ <object class="AdwSwitchRow" id="time_row">
+ <property name="title" translatable="yes">Share Local T_ime</property>
+ <property name="subtitle" translatable="yes">Share your current time with contacts to see their local time in return</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
</object>
</child>
<child>
diff --git a/main/data/style.css b/main/data/style.css
index 625534f2..29665ba7 100644
--- a/main/data/style.css
+++ b/main/data/style.css
@@ -233,6 +233,15 @@ window.dino-main .dino-sidebar frame.auto-complete list > row {
transition: none;
}
+/* Time offset warning */
+
+.dino-main .dino-conversation .time-offset {
+ background-color: var(--shade-color);
+ opacity: 80%;
+ padding: 12px;
+ border-radius: 6px 6px 0 0;
+}
+
/* Chat Input*/
/* These rules are direved from the libadwaita style for activateable entry rows */
diff --git a/main/src/ui/chat_input/view.vala b/main/src/ui/chat_input/view.vala
index dbb1f74e..8b57a08d 100644
--- a/main/src/ui/chat_input/view.vala
+++ b/main/src/ui/chat_input/view.vala
@@ -26,11 +26,18 @@ public class View : Box {
[GtkChild] public unowned MenuButton encryption_button;
[GtkChild] public unowned Separator file_separator;
[GtkChild] public unowned Label chat_input_status;
+ [GtkChild] public unowned Box unavailable_box;
+ [GtkChild] public unowned Image unavailable_icon;
+ [GtkChild] public unowned Label unavailable_label;
public EncryptionButton encryption_widget;
+ private bool is_dnd = false;
+ private bool is_night = false;
+
public View init(StreamInteractor stream_interactor) {
this.stream_interactor = stream_interactor;
+ stream_interactor.get_module(PresenceManager.IDENTITY).show_received.connect(on_show_received);
encryption_widget = new EncryptionButton(stream_interactor, encryption_button);
@@ -61,9 +68,99 @@ public class View : Box {
chat_text_view.text_view.buffer.text = entry_cache[conversation];
}
+ update_unavailable_message();
+
do_focus();
}
+ private void on_show_received(Jid jid, Account account) {
+ if (this.conversation.type_ == Conversation.Type.CHAT && this.conversation.counterpart.equals_bare(jid)) {
+ update_unavailable_message();
+ }
+ }
+
+ private void update_unavailable_message() {
+ if (conversation.type_ != Conversation.Type.CHAT) {
+ is_dnd = false;
+ is_night = false;
+ set_unavailable_message(null, null);
+ } else {
+ PresenceManager presence_manager = stream_interactor.get_module(PresenceManager.IDENTITY);
+ Gee.List<Jid>? full_jids = presence_manager.get_full_jids(conversation.counterpart, conversation.account);
+ if (full_jids != null) {
+ foreach (Jid full_jid in full_jids) {
+ if (presence_manager.get_last_show(full_jid, conversation.account) == Presence.Stanza.SHOW_DND) {
+ if (update_utc_offset_minutes_timeout != 0) {
+ Source.remove(update_utc_offset_minutes_timeout);
+ update_utc_offset_minutes_timeout = 0;
+ }
+ is_dnd = true;
+ set_unavailable_message(Markup.printf_escaped(_("%s has <b>paused their notifications</b>"), Util.get_conversation_display_name(stream_interactor, conversation)), "dino-bell-large-none-symbolic", true);
+ return;
+ }
+ }
+ }
+ is_dnd = false;
+ update_utc_offset_minutes();
+ }
+ }
+
+ private uint update_utc_offset_minutes_timeout = 0;
+ private void update_utc_offset_minutes() {
+ Conversation conversation = this.conversation;
+ if (update_utc_offset_minutes_timeout != 0) {
+ Source.remove(update_utc_offset_minutes_timeout);
+ update_utc_offset_minutes_timeout = 0;
+ }
+ if (conversation.type_ == Conversation.Type.CHAT) {
+ stream_interactor.get_module(EntityInfo.IDENTITY).get_utc_offset_minutes_for_bare_jid.begin(conversation.account, conversation.counterpart, (_, res) => {
+ set_utc_offset_minutes(conversation, stream_interactor.get_module(EntityInfo.IDENTITY).get_utc_offset_minutes_for_bare_jid.end(res));
+ update_utc_offset_minutes_timeout = WeakTimeout.add_once(60000 - (int) (new DateTime.now_utc().get_seconds()*1000d), this, update_utc_offset_minutes);
+ });
+ }
+ }
+
+ private void set_utc_offset_minutes(Conversation conversation, int utc_offset_minutes) {
+ if (this.conversation != conversation) return;
+ string? display_time = null;
+ if (utc_offset_minutes != int.MIN && new DateTime.now_local().get_utc_offset() / TimeSpan.MINUTE != utc_offset_minutes) {
+ var datetime = new DateTime.now(new TimeZone.offset(utc_offset_minutes * 60));
+ if (datetime.get_hour() >= 22 || datetime.get_hour() < 8) {
+ display_time = datetime.format(Util.is_24h_format() ?
+ /* xgettext:no-c-format */ /* Time in 24h format (w/o seconds) */ _("%H∶%M") :
+ /* xgettext:no-c-format */ /* Time in 12h format (w/o seconds) */ _("%l∶%M %p"));
+ }
+ }
+ is_night = (display_time != null);
+ if (!is_dnd) {
+ if (!is_night) {
+ set_unavailable_message(null, null);
+ } else {
+ set_unavailable_message(Markup.printf_escaped(_("It's <b>%s</b> for %s"), display_time, Util.get_conversation_display_name(stream_interactor, conversation)), "dino-clock-alt-symbolic", true);
+ }
+ }
+ }
+
+ private void set_unavailable_message(string? message, string? icon, bool use_markup = false) {
+ if (message == null) {
+ unavailable_box.visible = false;
+ } else {
+ if (use_markup) {
+ unavailable_label.set_markup(message);
+ } else {
+ unavailable_label.use_markup = use_markup;
+ unavailable_label.label = message;
+ }
+ unavailable_box.visible = true;
+ }
+ if (icon == null) {
+ unavailable_icon.opacity = 0;
+ } else {
+ unavailable_icon.icon_name = icon;
+ unavailable_icon.opacity = 1;
+ }
+ }
+
public void set_input_state(Plugins.InputFieldStatus.MessageType message_type) {
switch (message_type) {
case Plugins.InputFieldStatus.MessageType.NONE:
diff --git a/main/src/ui/conversation_details.vala b/main/src/ui/conversation_details.vala
index 404f357d..f9bae672 100644
--- a/main/src/ui/conversation_details.vala
+++ b/main/src/ui/conversation_details.vala
@@ -20,6 +20,11 @@ namespace Dino.Ui.ConversationDetails {
model.data_form_bak = model.data_form.stanza_node.to_string();
});
}
+ if (conversation.type_ == Conversation.Type.CHAT) {
+ stream_interactor.get_module(EntityInfo.IDENTITY).get_utc_offset_minutes_for_bare_jid.begin(conversation.account, conversation.counterpart, (_, res) => {
+ model.utc_offset_minutes = stream_interactor.get_module(EntityInfo.IDENTITY).get_utc_offset_minutes_for_bare_jid.end(res);
+ });
+ }
}
public void bind_dialog(Model.ConversationDetails model, ViewModel.ConversationDetails view_model, StreamInteractor stream_interactor) {
@@ -100,7 +105,7 @@ namespace Dino.Ui.ConversationDetails {
view_model.pin_changed.connect(() => {
model.conversation.pinned = model.conversation.pinned == 1 ? 0 : 1;
});
- view_model.block_changed.connect((action) => {
+ view_model.block_changed.connect((view_model, action) => {
switch (action) {
case USER:
stream_interactor.get_module(BlockingManager.IDENTITY).block(model.conversation.account, model.conversation.counterpart);
@@ -133,35 +138,67 @@ namespace Dino.Ui.ConversationDetails {
}
});
- view_model.notification_flipped.connect(() => {
+ view_model.notification_flipped.connect((view_model) => {
model.conversation.notify_setting = view_model.notification == ON ? Conversation.NotifySetting.OFF : Conversation.NotifySetting.ON;
});
}
+ private static string format_utc_offset_minutes(int utc_offset_minutes) {
+ var datetime = new DateTime.now(new TimeZone.offset(utc_offset_minutes * 60));
+ return datetime.format(Util.is_24h_format() ?
+ /* xgettext:no-c-format */ /* Weekday and time in 24h format (w/o seconds) */ _("%A, %H∶%M") :
+ /* xgettext:no-c-format */ /* Weekday and time in 12h format (w/o seconds) */ _("%A, %l∶%M %p"));
+ }
+
+ private uint get_interval_till_next_full_minute() {
+ return 60000 - (int) (new DateTime.now_utc().get_seconds()*1000d);
+ }
+
+ private static void notify_binding_once(Binding binding) {
+ binding.source.notify_property(binding.source_property);
+ }
+
public void set_about_rows(Model.ConversationDetails model, ViewModel.ConversationDetails view_model, StreamInteractor stream_interactor) {
+ Conversation conversation = model.conversation;
view_model.about_rows.append(new ViewModel.PreferencesRow.Text() {
title = _("XMPP Address"),
- text = model.conversation.counterpart.to_string()
+ text = conversation.counterpart.to_string()
});
- if (model.conversation.type_ == Conversation.Type.CHAT) {
+ if (conversation.type_ == Conversation.Type.CHAT) {
+ var display_name = model.display_name;
var about_row = new ViewModel.PreferencesRow.Entry() {
title = _("Display name"),
- text = model.display_name.display_name
+ text = display_name.display_name
};
- about_row.changed.connect(() => {
- if (about_row.text != model.display_name.display_name) {
- stream_interactor.get_module(RosterManager.IDENTITY).set_jid_handle(model.conversation.account, model.conversation.counterpart, about_row.text);
+ about_row.changed.connect((about_row) => {
+ if (about_row.text != display_name.display_name) {
+ stream_interactor.get_module(RosterManager.IDENTITY).set_jid_handle(conversation.account, conversation.counterpart, about_row.text);
}
});
view_model.about_rows.append(about_row);
+ var time_row = new ViewModel.PreferencesRow.Text() {
+ title = _("Local Time")
+ };
+ model.bind_property("utc-offset-minutes", time_row, "visible", BindingFlags.SYNC_CREATE, (binding, from, ref to) => {
+ int utc_offset_minutes = (int) from;
+ to = utc_offset_minutes != int.MIN;
+ return true;
+ });
+ model.bind_property("utc-offset-minutes", time_row, "text", BindingFlags.SYNC_CREATE, (binding, from, ref to) => {
+ var interval = get_interval_till_next_full_minute();
+ to = format_utc_offset_minutes((int) from);
+ WeakTimeout.add_once(interval, binding, notify_binding_once);
+ return true;
+ });
+ view_model.about_rows.append(time_row);
}
- if (model.conversation.type_ == Conversation.Type.GROUPCHAT) {
- var topic = stream_interactor.get_module(MucManager.IDENTITY).get_groupchat_subject(model.conversation.counterpart, model.conversation.account);
+ if (conversation.type_ == Conversation.Type.GROUPCHAT) {
+ var topic = stream_interactor.get_module(MucManager.IDENTITY).get_groupchat_subject(conversation.counterpart, conversation.account);
Ui.ViewModel.PreferencesRow.Any preferences_row = null;
- Jid? own_muc_jid = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(model.conversation.counterpart, model.conversation.account);
+ Jid? own_muc_jid = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account);
if (own_muc_jid != null) {
- Xep.Muc.Role? own_role = stream_interactor.get_module(MucManager.IDENTITY).get_role(own_muc_jid, model.conversation.account);
+ Xep.Muc.Role? own_role = stream_interactor.get_module(MucManager.IDENTITY).get_role(own_muc_jid, conversation.account);
if (own_role != null) {
if (own_role == MODERATOR) {
var preferences_row_entry = new ViewModel.PreferencesRow.Entry() {
@@ -170,7 +207,7 @@ namespace Dino.Ui.ConversationDetails {
};
preferences_row_entry.changed.connect(() => {
if (preferences_row_entry.text != topic) {
- stream_interactor.get_module(MucManager.IDENTITY).change_subject(model.conversation.account, model.conversation.counterpart, preferences_row_entry.text);
+ stream_interactor.get_module(MucManager.IDENTITY).change_subject(conversation.account, conversation.counterpart, preferences_row_entry.text);
}
});
preferences_row = preferences_row_entry;
@@ -205,8 +242,9 @@ namespace Dino.Ui.ConversationDetails {
});
Plugins.ContactDetails contact_details = new Plugins.ContactDetails();
+ var settings_rows = dialog.model.settings_rows;
contact_details.add_settings_action_row.connect((entry_row_model) => {
- dialog.model.settings_rows.append((Ui.ViewModel.PreferencesRow.Any) entry_row_model);
+ settings_rows.append((Ui.ViewModel.PreferencesRow.Any) entry_row_model);
});
Application app = GLib.Application.get_default() as Application;
app.plugin_registry.register_contact_details_entry(new ContactDetails.SettingsProvider(stream_interactor));
diff --git a/main/src/ui/util/preference_group.vala b/main/src/ui/util/preference_group.vala
index aa680e68..3911bb80 100644
--- a/main/src/ui/util/preference_group.vala
+++ b/main/src/ui/util/preference_group.vala
@@ -47,63 +47,55 @@ namespace Dino.Ui.Util {
return preference_group;
}
+ private static bool null_string_to_empty(GLib.Binding binding, GLib.Value from_value, ref GLib.Value to_value) {
+ var str = (string) from_value;
+ to_value = str ?? "";
+ return true;
+ }
+
public Adw.PreferencesRow? row_to_preference_row(ViewModel.PreferencesRow.Any preferences_row) {
+ Adw.PreferencesRow? view = null;
+
var entry_view_model = preferences_row as ViewModel.PreferencesRow.Entry;
if (entry_view_model != null) {
- Adw.EntryRow view = new Adw.EntryRow() { title = entry_view_model.title, show_apply_button=true };
+ view = new Adw.EntryRow() { show_apply_button=true };
if (preferences_row.media_uri != null) {
var bytes = Xmpp.get_data_for_uri(preferences_row.media_uri);
Picture picture = new Picture.for_paintable(Texture.from_bytes(bytes));
- view.add_suffix(picture);
+ ((Adw.EntryRow) view).add_suffix(picture);
}
- entry_view_model.bind_property("text", view, "text", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL, (_, from, ref to) => {
- var str = (string) from;
- to = str ?? "";
- return true;
- });
- view.apply.connect(() => {
+ entry_view_model.bind_property("text", view, "text", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL, null_string_to_empty);
+ ((Adw.EntryRow) view).apply.connect(() => {
entry_view_model.changed();
});
- return view;
}
var password_view_model = preferences_row as ViewModel.PreferencesRow.PrivateText;
if (password_view_model != null) {
- Adw.PasswordEntryRow view = new Adw.PasswordEntryRow() { title = password_view_model.title, show_apply_button=true };
- password_view_model.bind_property("text", view, "text", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL, (_, from, ref to) => {
- var str = (string) from;
- to = str ?? "";
- return true;
- });
- view.apply.connect(() => {
+ view = new Adw.PasswordEntryRow() { show_apply_button=true };
+ password_view_model.bind_property("text", view, "text", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL, null_string_to_empty);
+ ((Adw.EntryRow) view).apply.connect(() => {
password_view_model.changed();
});
-
- return view;
}
var row_text = preferences_row as ViewModel.PreferencesRow.Text;
if (row_text != null) {
- var view = new Adw.ActionRow() {
- title = row_text.title,
- subtitle = row_text.text,
+ view = new Adw.ActionRow() {
subtitle_selectable = true
};
+ row_text.bind_property("text", view, "subtitle", BindingFlags.SYNC_CREATE, null_string_to_empty);
view.add_css_class("property");
Util.force_css(view, "row.property > box.header > box.title > .title { font-weight: 400; font-size: 9pt; opacity: 0.55; }");
Util.force_css(view, "row.property > box.header > box.title > .subtitle { font-size: inherit; opacity: 1; }");
- return view;
}
var toggle_view_model = preferences_row as ViewModel.PreferencesRow.Toggle;
if (toggle_view_model != null) {
- var view = new Adw.ActionRow() { title = toggle_view_model.title, subtitle = toggle_view_model.subtitle ?? "" };
- var toggle = new Switch() { valign = Align.CENTER };
- view.activatable_widget = toggle;
- view.add_suffix(toggle);
- toggle_view_model.bind_property("state", toggle, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
- return view;
+ view = new Adw.SwitchRow();
+ toggle_view_model.bind_property("subtitle", view, "subtitle", BindingFlags.SYNC_CREATE, null_string_to_empty);
+ toggle_view_model.bind_property("state", view, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
}
var combobox_view_model = preferences_row as ViewModel.PreferencesRow.ComboBox;
@@ -112,21 +104,24 @@ namespace Dino.Ui.Util {
foreach (string text in combobox_view_model.items) {
string_list.append(text);
}
- var view = new Adw.ComboRow() { title = combobox_view_model.title, subtitle = combobox_view_model.subtitle ?? "" };
- view.model = string_list;
+ view = new Adw.ComboRow();
+ combobox_view_model.bind_property("subtitle", view, "subtitle", BindingFlags.SYNC_CREATE, null_string_to_empty);
+ ((Adw.ComboRow)view).model = string_list;
combobox_view_model.bind_property("active-item", view, "selected", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
- return view;
}
var button_view_model = preferences_row as ViewModel.PreferencesRow.Button;
if (button_view_model != null) {
- var view = new Adw.ActionRow() { title = button_view_model.title, subtitle = button_view_model.subtitle ?? "" };
+ view = new Adw.ActionRow();
+ button_view_model.bind_property("subtitle", view, "subtitle", BindingFlags.SYNC_CREATE, null_string_to_empty);
var button = new Button.with_label(button_view_model.button_text) { valign = Align.CENTER };
- view.add_suffix(button);
+ ((Adw.ActionRow)view).add_suffix(button);
button.clicked.connect(() => button_view_model.clicked());
- return view;
}
- return null;
+ preferences_row.bind_property("title", view, "title", BindingFlags.SYNC_CREATE);
+ preferences_row.bind_property("visible", view, "visible", BindingFlags.SYNC_CREATE);
+
+ return view;
}
} \ No newline at end of file
diff --git a/main/src/view_model/conversation_details.vala b/main/src/view_model/conversation_details.vala
index 26379dab..c8da2ee0 100644
--- a/main/src/view_model/conversation_details.vala
+++ b/main/src/view_model/conversation_details.vala
@@ -84,6 +84,7 @@ public class Dino.Ui.Model.ConversationDetails : Object {
public string? data_form_bak;
public bool blocked { get; set; }
public bool domain_blocked { get; set; }
+ public int utc_offset_minutes { get; set; default = int.MIN; }
public GLib.ListStore members = new GLib.ListStore(typeof(Ui.Model.ConferenceMember));
diff --git a/main/src/view_model/preferences_dialog.vala b/main/src/view_model/preferences_dialog.vala
index af00494d..20e11ae3 100644
--- a/main/src/view_model/preferences_dialog.vala
+++ b/main/src/view_model/preferences_dialog.vala
@@ -109,6 +109,7 @@ public class Dino.Ui.ViewModel.PreferencesDialog : Object {
var settings = Dino.Application.get_default().settings;
settings.bind_property("send-typing", general_page, "send-typing", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
settings.bind_property("send-marker", general_page, "send-marker", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+ settings.bind_property("share-time", general_page, "share-time", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
settings.bind_property("notifications", general_page, "notifications", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
settings.bind_property("convert-utf8-smileys", general_page, "convert-emojis", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
}
diff --git a/main/src/view_model/preferences_row.vala b/main/src/view_model/preferences_row.vala
index 4ca2f2df..d0f64979 100644
--- a/main/src/view_model/preferences_row.vala
+++ b/main/src/view_model/preferences_row.vala
@@ -6,6 +6,7 @@ using Gee;
namespace Dino.Ui.ViewModel.PreferencesRow {
public abstract class Any : Object {
public string title { get; set; }
+ public bool visible { get; set; default=true; }
public string? media_type { get; set; }
public string? media_uri { get; set; }
diff --git a/main/src/windows/preferences_window/general_preferences_page.vala b/main/src/windows/preferences_window/general_preferences_page.vala
index 1e81a1b7..0dcf2118 100644
--- a/main/src/windows/preferences_window/general_preferences_page.vala
+++ b/main/src/windows/preferences_window/general_preferences_page.vala
@@ -3,6 +3,7 @@ using Gtk;
public class Dino.Ui.ViewModel.GeneralPreferencesPage : Object {
public bool send_typing { get; set; }
public bool send_marker { get; set; }
+ public bool share_time { get; set; }
public bool notifications { get; set; }
public bool convert_emojis { get; set; }
}
@@ -11,6 +12,7 @@ public class Dino.Ui.ViewModel.GeneralPreferencesPage : Object {
public class Dino.Ui.GeneralPreferencesPage : Adw.PreferencesPage {
[GtkChild] private unowned Adw.SwitchRow typing_row;
[GtkChild] private unowned Adw.SwitchRow marker_row;
+ [GtkChild] private unowned Adw.SwitchRow time_row;
[GtkChild] private unowned Adw.SwitchRow notification_row;
[GtkChild] private unowned Adw.SwitchRow emoji_row;
@@ -29,6 +31,7 @@ public class Dino.Ui.GeneralPreferencesPage : Adw.PreferencesPage {
model_bindings = new Binding[] {
model.bind_property("send-typing", typing_row, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL),
model.bind_property("send-marker", marker_row, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL),
+ model.bind_property("share-time", time_row, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL),
model.bind_property("notifications", notification_row, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL),
model.bind_property("convert-emojis", emoji_row, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL)
};
diff --git a/xmpp-vala/meson.build b/xmpp-vala/meson.build
index 4769a8a6..b035e367 100644
--- a/xmpp-vala/meson.build
+++ b/xmpp-vala/meson.build
@@ -93,6 +93,7 @@ sources = files(
'src/module/xep/0191_blocking_command.vala',
'src/module/xep/0198_stream_management.vala',
'src/module/xep/0199_ping.vala',
+ 'src/module/xep/0202_entity_time.vala',
'src/module/xep/0203_delayed_delivery.vala',
'src/module/xep/0215_external_service_discovery.vala',
'src/module/xep/0231_bits_of_binary.vala',
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) {