aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfiaxh <git@mx.ax.lt>2017-03-09 15:34:32 +0100
committerfiaxh <git@mx.ax.lt>2017-03-09 15:45:03 +0100
commit5fc0435cc1227bf445d06a3931343020faaecd10 (patch)
tree329041d3b2545fc445e9f175d3d5fff755fd110b
parentb1e6e51c4f79f57f0a01b183ef185408fb22cc36 (diff)
downloaddino-5fc0435cc1227bf445d06a3931343020faaecd10.tar.gz
dino-5fc0435cc1227bf445d06a3931343020faaecd10.zip
Save unsent messages (acc offline etc) and send later; don't send pgp messages if pgp error
-rw-r--r--client/src/entity/conversation.vala18
-rw-r--r--client/src/entity/message.vala4
-rw-r--r--client/src/service/chat_interaction.vala4
-rw-r--r--client/src/service/conversation_manager.vala13
-rw-r--r--client/src/service/database.vala55
-rw-r--r--client/src/service/message_manager.vala113
-rw-r--r--client/src/service/muc_manager.vala4
-rw-r--r--client/src/service/stream_interactor.vala2
-rw-r--r--client/src/ui/conversation_selector/list.vala2
-rw-r--r--client/src/ui/conversation_summary/merged_message_item.vala8
-rw-r--r--client/src/ui/conversation_summary/view.vala3
-rw-r--r--client/src/ui/conversation_titlebar.vala20
-rw-r--r--qlite/src/update_builder.vala1
-rw-r--r--vala-xmpp/CMakeLists.txt1
-rw-r--r--vala-xmpp/src/module/xep/0082_date_time_profiles.vala41
-rw-r--r--vala-xmpp/src/module/xep/0203_delayed_delivery.vala28
16 files changed, 204 insertions, 113 deletions
diff --git a/client/src/entity/conversation.vala b/client/src/entity/conversation.vala
index d5c861d9..2da6dce3 100644
--- a/client/src/entity/conversation.vala
+++ b/client/src/entity/conversation.vala
@@ -3,19 +3,23 @@ public class Conversation : Object {
public signal void object_updated(Conversation conversation);
- public const int ENCRYPTION_UNENCRYPTED = 0;
- public const int ENCRYPTION_PGP = 1;
+ public enum Encryption {
+ UNENCRYPTED,
+ PGP
+ }
- public const int TYPE_CHAT = 0;
- public const int TYPE_GROUPCHAT = 1;
+ public enum Type {
+ CHAT,
+ GROUPCHAT
+ }
public int id { get; set; }
public Account account { get; private set; }
public Jid counterpart { get; private set; }
public bool active { get; set; }
public DateTime last_active { get; set; }
- public int encryption { get; set; }
- public int? type_ { get; set; }
+ public Encryption encryption { get; set; }
+ public Type? type_ { get; set; }
public Message read_up_to { get; set; }
public Conversation(Jid jid, Account account) {
@@ -23,7 +27,7 @@ public class Conversation : Object {
this.account = account;
this.active = false;
this.last_active = new DateTime.from_unix_utc(0);
- this.encryption = ENCRYPTION_UNENCRYPTED;
+ this.encryption = Encryption.UNENCRYPTED;
}
public Conversation.with_id(Jid jid, Account account, int id) {
diff --git a/client/src/entity/message.vala b/client/src/entity/message.vala
index 042166b0..65d05bdf 100644
--- a/client/src/entity/message.vala
+++ b/client/src/entity/message.vala
@@ -11,7 +11,9 @@ public class Dino.Entities.Message : Object {
NONE,
RECEIVED,
READ,
- ACKNOWLEDGED
+ ACKNOWLEDGED,
+ UNSENT,
+ WONTSEND
}
public enum Encryption {
diff --git a/client/src/service/chat_interaction.vala b/client/src/service/chat_interaction.vala
index ed805a93..cd6907fa 100644
--- a/client/src/service/chat_interaction.vala
+++ b/client/src/service/chat_interaction.vala
@@ -47,7 +47,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
public void on_message_entered(Conversation conversation) {
if (Settings.instance().send_read) {
- if (!last_input_interaction.has_key(conversation) && conversation.type_ != Conversation.TYPE_GROUPCHAT) {
+ if (!last_input_interaction.has_key(conversation) && conversation.type_ != Conversation.Type.GROUPCHAT) {
send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_COMPOSING);
}
}
@@ -82,7 +82,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
}
private void check_send_read() {
- if (selected_conversation == null || selected_conversation.type_ == Conversation.TYPE_GROUPCHAT) return;
+ if (selected_conversation == null || selected_conversation.type_ == Conversation.Type.GROUPCHAT) return;
Entities.Message? message = MessageManager.get_instance(stream_interactor).get_last_message(selected_conversation);
if (message != null && message.direction == Entities.Message.DIRECTION_RECEIVED &&
message.stanza != null && !message.equals(selected_conversation.read_up_to)) {
diff --git a/client/src/service/conversation_manager.vala b/client/src/service/conversation_manager.vala
index 5337f007..716c9b39 100644
--- a/client/src/service/conversation_manager.vala
+++ b/client/src/service/conversation_manager.vala
@@ -27,6 +27,7 @@ public class ConversationManager : StreamInteractionModule, Object {
stream_interactor.account_added.connect(on_account_added);
MucManager.get_instance(stream_interactor).groupchat_joined.connect(on_groupchat_joined);
MessageManager.get_instance(stream_interactor).pre_message_received.connect(on_message_received);
+ MessageManager.get_instance(stream_interactor).message_sent.connect(on_message_sent);
}
public Conversation? get_conversation(Jid jid, Account account) {
@@ -37,12 +38,12 @@ public class ConversationManager : StreamInteractionModule, Object {
}
public Conversation get_add_conversation(Jid jid, Account account) {
- ensure_add_conversation(jid, account, Conversation.TYPE_CHAT);
+ ensure_add_conversation(jid, account, Conversation.Type.CHAT);
return get_conversation(jid, account);
}
public void ensure_start_conversation(Jid jid, Account account) {
- ensure_add_conversation(jid, account, Conversation.TYPE_CHAT);
+ ensure_add_conversation(jid, account, Conversation.Type.CHAT);
Conversation? conversation = get_conversation(jid, account);
if (conversation != null) {
conversation.last_active = new DateTime.now_utc();
@@ -73,12 +74,16 @@ public class ConversationManager : StreamInteractionModule, Object {
ensure_start_conversation(conversation.counterpart, conversation.account);
}
+ private void on_message_sent(Entities.Message message, Conversation conversation) {
+ conversation.last_active = message.time;
+ }
+
private void on_groupchat_joined(Account account, Jid jid, string nick) {
- ensure_add_conversation(jid, account, Conversation.TYPE_GROUPCHAT);
+ ensure_add_conversation(jid, account, Conversation.Type.GROUPCHAT);
ensure_start_conversation(jid, account);
}
- private void ensure_add_conversation(Jid jid, Account account, int type) {
+ private void ensure_add_conversation(Jid jid, Account account, Conversation.Type type) {
if (conversations.has_key(account) && !conversations[account].has_key(jid)) {
Conversation conversation = new Conversation(jid, account);
conversation.type_ = type;
diff --git a/client/src/service/database.vala b/client/src/service/database.vala
index 6428d83f..13be6222 100644
--- a/client/src/service/database.vala
+++ b/client/src/service/database.vala
@@ -36,11 +36,11 @@ public class Database : Qlite.Database {
public class MessageTable : Table {
public Column<int> id = new Column.Integer("id") { primary_key = true, auto_increment = true };
public Column<string> stanza_id = new Column.Text("stanza_id");
- public Column<int> account_id = new Column.Integer("account_id");
- public Column<int> counterpart_id = new Column.Integer("counterpart_id");
+ public Column<int> account_id = new Column.Integer("account_id") { not_null = true };
+ public Column<int> counterpart_id = new Column.Integer("counterpart_id") { not_null = true };
public Column<string> counterpart_resource = new Column.Text("counterpart_resource");
public Column<string> our_resource = new Column.Text("our_resource");
- public Column<bool> direction = new Column.BoolInt("direction");
+ public Column<bool> direction = new Column.BoolInt("direction") { not_null = true };
public Column<int> type_ = new Column.Integer("type");
public Column<long> time = new Column.Long("time");
public Column<long> local_time = new Column.Long("local_time");
@@ -205,24 +205,20 @@ public class Database : Qlite.Database {
}
public void add_message(Message new_message, Account account) {
- if (new_message.body == null || new_message.stanza_id == null) {
- return;
- }
-
- new_message.id = (int) message.insert()
- .value(message.stanza_id, new_message.stanza_id)
- .value(message.account_id, new_message.account.id)
- .value(message.counterpart_id, get_jid_id(new_message.counterpart))
- .value(message.counterpart_resource, new_message.counterpart.resourcepart)
- .value(message.our_resource, new_message.ourpart.resourcepart)
- .value(message.direction, new_message.direction)
- .value(message.type_, new_message.type_)
- .value(message.time, (long) new_message.time.to_unix())
- .value(message.local_time, (long) new_message.local_time.to_unix())
- .value(message.body, new_message.body)
- .value(message.encryption, new_message.encryption)
- .value(message.marked, new_message.marked)
- .perform();
+ InsertBuilder builder = message.insert()
+ .value(message.account_id, new_message.account.id)
+ .value(message.counterpart_id, get_jid_id(new_message.counterpart))
+ .value(message.counterpart_resource, new_message.counterpart.resourcepart)
+ .value(message.our_resource, new_message.ourpart.resourcepart)
+ .value(message.direction, new_message.direction)
+ .value(message.type_, new_message.type_)
+ .value(message.time, (long) new_message.time.to_unix())
+ .value(message.local_time, (long) new_message.local_time.to_unix())
+ .value(message.body, new_message.body)
+ .value(message.encryption, new_message.encryption)
+ .value(message.marked, new_message.marked);
+ if (new_message.stanza_id != null) builder.value(message.stanza_id, new_message.stanza_id);
+ new_message.id = (int) builder.perform();
if (new_message.real_jid != null) {
real_jid.insert()
@@ -288,6 +284,14 @@ public class Database : Qlite.Database {
return ret;
}
+ public Gee.List<Message> get_unsend_messages(Account account) {
+ Gee.List<Message> ret = new ArrayList<Message>();
+ foreach (Row row in message.select().with(message.marked, "=", (int) Message.Marked.UNSENT)) {
+ ret.add(get_message_from_row(row));
+ }
+ return ret;
+ }
+
public bool contains_message(Message query_message, Account account) {
int jid_id = get_jid_id(query_message.counterpart);
return message.select()
@@ -295,6 +299,9 @@ public class Database : Qlite.Database {
.with(message.stanza_id, "=", query_message.stanza_id)
.with(message.counterpart_id, "=", jid_id)
.with(message.counterpart_resource, "=", query_message.counterpart.resourcepart)
+ .with(message.body, "=", query_message.body)
+ .with(message.time, "<", (long) query_message.time.add_minutes(1).to_unix())
+ .with(message.time, ">", (long) query_message.time.add_minutes(-1).to_unix())
.count() > 0;
}
@@ -332,6 +339,8 @@ public class Database : Qlite.Database {
new_message.marked = (Message.Marked) row[message.marked];
new_message.encryption = (Message.Encryption) row[message.encryption];
new_message.real_jid = get_real_jid_for_message(new_message);
+
+ new_message.notify.connect(on_message_update);
return new_message;
}
@@ -386,8 +395,8 @@ public class Database : Qlite.Database {
new_conversation.active = row[conversation.active];
int64? last_active = row[conversation.last_active];
if (last_active != null) new_conversation.last_active = new DateTime.from_unix_utc(last_active);
- new_conversation.type_ = row[conversation.type_];
- new_conversation.encryption = row[conversation.encryption];
+ new_conversation.type_ = (Conversation.Type) row[conversation.type_];
+ new_conversation.encryption = (Conversation.Encryption) row[conversation.encryption];
int? read_up_to = row[conversation.read_up_to];
if (read_up_to != null) new_conversation.read_up_to = get_message_by_id(read_up_to);
diff --git a/client/src/service/message_manager.vala b/client/src/service/message_manager.vala
index a268e619..054db518 100644
--- a/client/src/service/message_manager.vala
+++ b/client/src/service/message_manager.vala
@@ -6,7 +6,7 @@ using Dino.Entities;
namespace Dino {
public class MessageManager : StreamInteractionModule, Object {
- public const string id = "message_manager";
+ public const string ID = "message_manager";
public signal void pre_message_received(Entities.Message message, Conversation conversation);
public signal void message_received(Entities.Message message, Conversation conversation);
@@ -25,46 +25,16 @@ public class MessageManager : StreamInteractionModule, Object {
this.stream_interactor = stream_interactor;
this.db = db;
stream_interactor.account_added.connect(on_account_added);
+ stream_interactor.connection_manager.connection_state_changed.connect((account, state) => {
+ if (state == ConnectionManager.ConnectionState.CONNECTED) send_unsent_messages(account);
+ });
}
public void send_message(string text, Conversation conversation) {
- Entities.Message message = new Entities.Message();
- message.account = conversation.account;
- message.body = text;
- message.time = new DateTime.now_utc();
- message.local_time = new DateTime.now_utc();
- message.direction = Entities.Message.DIRECTION_SENT;
- message.counterpart = conversation.counterpart;
- message.ourpart = new Jid(conversation.account.bare_jid.to_string() + "/" + conversation.account.resourcepart);
-
- Core.XmppStream stream = stream_interactor.get_stream(conversation.account);
-
- if (stream != null) {
- Xmpp.Message.Stanza new_message = new Xmpp.Message.Stanza();
- new_message.to = message.counterpart.to_string();
- new_message.body = message.body;
- if (conversation.type_ == Conversation.TYPE_GROUPCHAT) {
- new_message.type_ = Xmpp.Message.Stanza.TYPE_GROUPCHAT;
- } else {
- new_message.type_ = Xmpp.Message.Stanza.TYPE_CHAT;
- }
- if (conversation.encryption == Conversation.ENCRYPTION_PGP) {
- string? key_id = PgpManager.get_instance(stream_interactor).get_key_id(conversation.account, message.counterpart);
- if (key_id != null) {
- bool encrypted = Xep.Pgp.Module.get_module(stream).encrypt(new_message, key_id);
- if (encrypted) message.encryption = Entities.Message.Encryption.PGP;
- }
- }
- Xmpp.Message.Module.get_module(stream).send_message(stream, new_message);
- message.stanza_id = new_message.id;
- message.stanza = new_message;
- db.add_message(message, conversation.account);
- } else {
- // save for resend
- }
-
- conversation.last_active = message.time;
+ Entities.Message message = create_out_message(text, conversation);
add_message(message, conversation);
+ db.add_message(message, conversation.account);
+ send_xmpp_message(message, conversation);
message_sent(message, conversation);
}
@@ -97,17 +67,26 @@ public class MessageManager : StreamInteractionModule, Object {
}
public string get_id() {
- return id;
+ return ID;
}
public static MessageManager? get_instance(StreamInteractor stream_interactor) {
- return (MessageManager) stream_interactor.get_module(id);
+ return (MessageManager) stream_interactor.get_module(ID);
}
private void on_account_added(Account account) {
stream_interactor.module_manager.message_modules[account].received_message.connect( (stream, message) => {
on_message_received(account, message);
});
+ stream_interactor.stream_negotiated.connect(send_unsent_messages);
+ }
+
+ private void send_unsent_messages(Account account) {
+ Gee.List<Entities.Message> unsend_messages = db.get_unsend_messages(account);
+ foreach (Entities.Message message in unsend_messages) {
+ Conversation conversation = ConversationManager.get_instance(stream_interactor).get_conversation(message.counterpart, account);
+ send_xmpp_message(message, conversation, true);
+ }
}
private void on_message_received(Account account, Xmpp.Message.Stanza message) {
@@ -128,10 +107,8 @@ public class MessageManager : StreamInteractionModule, Object {
new_message.body = message.body;
new_message.stanza = message;
new_message.set_type_string(message.type_);
- new_message.time = Xep.DelayedDelivery.Module.get_send_time(message);
- if (new_message.time == null) {
- new_message.time = new DateTime.now_utc();
- }
+ Xep.DelayedDelivery.MessageFlag? deleyed_delivery_flag = Xep.DelayedDelivery.MessageFlag.get_flag(message);
+ new_message.time = deleyed_delivery_flag != null ? deleyed_delivery_flag.datetime : new DateTime.now_utc();
new_message.local_time = new DateTime.now_utc();
if (Xep.Pgp.MessageFlag.get_flag(message) != null) {
new_message.encryption = Entities.Message.Encryption.PGP;
@@ -161,6 +138,56 @@ public class MessageManager : StreamInteractionModule, Object {
}
messages[conversation].add(message);
}
+
+ private Entities.Message create_out_message(string text, Conversation conversation) {
+ Entities.Message message = new Entities.Message();
+ message.stanza_id = UUID.generate_random_unparsed();
+ message.account = conversation.account;
+ message.body = text;
+ message.time = new DateTime.now_utc();
+ message.local_time = new DateTime.now_utc();
+ message.direction = Entities.Message.DIRECTION_SENT;
+ message.counterpart = conversation.counterpart;
+ message.ourpart = new Jid(conversation.account.bare_jid.to_string() + "/" + conversation.account.resourcepart);
+
+ if (conversation.encryption == Conversation.Encryption.PGP) {
+ message.encryption = Entities.Message.Encryption.PGP;
+ }
+ return message;
+ }
+
+ private void send_xmpp_message(Entities.Message message, Conversation conversation, bool delayed = false) {
+ Core.XmppStream stream = stream_interactor.get_stream(conversation.account);
+ message.marked = Entities.Message.Marked.NONE;
+ if (stream != null) {
+ Xmpp.Message.Stanza new_message = new Xmpp.Message.Stanza(message.stanza_id);
+ new_message.to = message.counterpart.to_string();
+ new_message.body = message.body;
+ if (conversation.type_ == Conversation.Type.GROUPCHAT) {
+ new_message.type_ = Xmpp.Message.Stanza.TYPE_GROUPCHAT;
+ } else {
+ new_message.type_ = Xmpp.Message.Stanza.TYPE_CHAT;
+ }
+ if (message.encryption == Entities.Message.Encryption.PGP) {
+ string? key_id = PgpManager.get_instance(stream_interactor).get_key_id(conversation.account, message.counterpart);
+ if (key_id != null) {
+ bool encrypted = Xep.Pgp.Module.get_module(stream).encrypt(new_message, key_id);
+ if (!encrypted) {
+ message.marked = Entities.Message.Marked.WONTSEND;
+ return;
+ }
+ }
+ }
+ if (delayed) {
+ Xmpp.Xep.DelayedDelivery.Module.get_module(stream).set_message_delay(new_message, message.time);
+ }
+ Xmpp.Message.Module.get_module(stream).send_message(stream, new_message);
+ message.stanza_id = new_message.id;
+ message.stanza = new_message;
+ } else {
+ message.marked = Entities.Message.Marked.UNSENT;
+ }
+ }
}
} \ No newline at end of file
diff --git a/client/src/service/muc_manager.vala b/client/src/service/muc_manager.vala
index 8f6339a5..be23d391 100644
--- a/client/src/service/muc_manager.vala
+++ b/client/src/service/muc_manager.vala
@@ -66,7 +66,7 @@ public class MucManager : StreamInteractionModule, Object {
public bool is_groupchat(Jid jid, Account account) {
Conversation? conversation = ConversationManager.get_instance(stream_interactor).get_conversation(jid, account);
- return !jid.is_full() && conversation != null && conversation.type_ == Conversation.TYPE_GROUPCHAT;
+ return !jid.is_full() && conversation != null && conversation.type_ == Conversation.Type.GROUPCHAT;
}
public bool is_groupchat_occupant(Jid jid, Account account) {
@@ -162,7 +162,7 @@ public class MucManager : StreamInteractionModule, Object {
}
private void on_pre_message_received(Entities.Message message, Conversation conversation) {
- if (conversation.type_ != Conversation.TYPE_GROUPCHAT) return;
+ if (conversation.type_ != Conversation.Type.GROUPCHAT) return;
Core.XmppStream stream = stream_interactor.get_stream(conversation.account);
if (stream == null) return;
if (Xep.DelayedDelivery.MessageFlag.get_flag(message.stanza) == null) {
diff --git a/client/src/service/stream_interactor.vala b/client/src/service/stream_interactor.vala
index 56591cf0..f3859e3b 100644
--- a/client/src/service/stream_interactor.vala
+++ b/client/src/service/stream_interactor.vala
@@ -4,6 +4,7 @@ using Xmpp;
using Dino.Entities;
namespace Dino {
+
public class StreamInteractor {
public signal void account_added(Account account);
@@ -65,4 +66,5 @@ public class StreamInteractor {
public interface StreamInteractionModule : Object {
internal abstract string get_id();
}
+
} \ No newline at end of file
diff --git a/client/src/ui/conversation_selector/list.vala b/client/src/ui/conversation_selector/list.vala
index b114c3fa..e6a5231c 100644
--- a/client/src/ui/conversation_selector/list.vala
+++ b/client/src/ui/conversation_selector/list.vala
@@ -95,7 +95,7 @@ public class List : ListBox {
public void add_conversation(Conversation conversation) {
ConversationRow row;
if (!rows.has_key(conversation)) {
- if (conversation.type_ == Conversation.TYPE_GROUPCHAT) {
+ if (conversation.type_ == Conversation.Type.GROUPCHAT) {
row = new GroupchatRow(stream_interactor, conversation);
} else {
row = new ChatRow(stream_interactor, conversation);
diff --git a/client/src/ui/conversation_summary/merged_message_item.vala b/client/src/ui/conversation_summary/merged_message_item.vala
index b1e99d3e..b73e8b4f 100644
--- a/client/src/ui/conversation_summary/merged_message_item.vala
+++ b/client/src/ui/conversation_summary/merged_message_item.vala
@@ -68,10 +68,16 @@ public class MergedMessageItem : Grid {
}
private void update_received() {
+ received_image.visible = true;
bool all_received = true;
bool all_read = true;
foreach (Message message in messages) {
- if (message.marked != Message.Marked.READ) {
+ if (message.marked == Message.Marked.WONTSEND) {
+ Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default();
+ Gtk.IconInfo? icon_info = icon_theme.lookup_icon("dialog-warning-symbolic", IconSize.SMALL_TOOLBAR, 0);
+ received_image.set_from_pixbuf(icon_info.load_symbolic({1,0,0,1}));
+ return;
+ } else if (message.marked != Message.Marked.READ) {
all_read = false;
if (message.marked != Message.Marked.RECEIVED) {
all_received = false;
diff --git a/client/src/ui/conversation_summary/view.vala b/client/src/ui/conversation_summary/view.vala
index 0ea1a32c..59cf88aa 100644
--- a/client/src/ui/conversation_summary/view.vala
+++ b/client/src/ui/conversation_summary/view.vala
@@ -203,7 +203,8 @@ public class View : Box {
return message_item != null &&
message_item.from.equals(message.from) &&
message_item.messages.get(0).encryption == message.encryption &&
- message.time.difference(message_item.initial_time) < TimeSpan.MINUTE;
+ message.time.difference(message_item.initial_time) < TimeSpan.MINUTE &&
+ (message_item.messages.get(0).marked == Entities.Message.Marked.WONTSEND) == (message.marked == Entities.Message.Marked.WONTSEND);
}
private void force_alloc_width(Widget widget, int width) {
diff --git a/client/src/ui/conversation_titlebar.vala b/client/src/ui/conversation_titlebar.vala
index cd21353c..25304e1a 100644
--- a/client/src/ui/conversation_titlebar.vala
+++ b/client/src/ui/conversation_titlebar.vala
@@ -41,19 +41,19 @@ public class Dino.Ui.ConversationTitlebar : Gtk.HeaderBar {
string? pgp_id = PgpManager.get_instance(stream_interactor).get_key_id(conversation.account, conversation.counterpart);
button_pgp.set_sensitive(pgp_id != null);
switch (conversation.encryption) {
- case Conversation.ENCRYPTION_UNENCRYPTED:
+ case Conversation.Encryption.UNENCRYPTED:
button_unencrypted.set_active(true);
break;
- case Conversation.ENCRYPTION_PGP:
+ case Conversation.Encryption.PGP:
button_pgp.set_active(true);
break;
}
}
private void update_encryption_menu_icon() {
- encryption_button.visible = conversation.type_ == Conversation.TYPE_CHAT;
- if (conversation.type_ == Conversation.TYPE_CHAT) {
- if (conversation.encryption == Conversation.ENCRYPTION_UNENCRYPTED) {
+ encryption_button.visible = (conversation.type_ == Conversation.Type.CHAT);
+ if (conversation.type_ == Conversation.Type.CHAT) {
+ if (conversation.encryption == Conversation.Encryption.UNENCRYPTED) {
encryption_button.set_image(new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON));
} else {
encryption_button.set_image(new Image.from_icon_name("changes-prevent-symbolic", IconSize.BUTTON));
@@ -62,8 +62,8 @@ public class Dino.Ui.ConversationTitlebar : Gtk.HeaderBar {
}
private void update_groupchat_menu() {
- groupchat_button.visible = conversation.type_ == Conversation.TYPE_GROUPCHAT;
- if (conversation.type_ == Conversation.TYPE_GROUPCHAT) {
+ groupchat_button.visible = conversation.type_ == Conversation.Type.GROUPCHAT;
+ if (conversation.type_ == Conversation.Type.GROUPCHAT) {
groupchat_button.set_use_popover(true);
Popover popover = new Popover(null);
OccupantList occupant_list = new OccupantList(stream_interactor, conversation);
@@ -80,7 +80,7 @@ public class Dino.Ui.ConversationTitlebar : Gtk.HeaderBar {
private void update_subtitle(string? subtitle = null) {
if (subtitle != null) {
set_subtitle(subtitle);
- } else if (conversation.type_ == Conversation.TYPE_GROUPCHAT) {
+ } else if (conversation.type_ == Conversation.Type.GROUPCHAT) {
string subject = MucManager.get_instance(stream_interactor).get_groupchat_subject(conversation.counterpart, conversation.account);
set_subtitle(subject != "" ? subject : null);
} else {
@@ -106,9 +106,9 @@ public class Dino.Ui.ConversationTitlebar : Gtk.HeaderBar {
button_unencrypted.toggled.connect(() => {
if (conversation != null) {
if (button_unencrypted.get_active()) {
- conversation.encryption = Conversation.ENCRYPTION_UNENCRYPTED;
+ conversation.encryption = Conversation.Encryption.UNENCRYPTED;
} else if (button_pgp.get_active()) {
- conversation.encryption = Conversation.ENCRYPTION_PGP;
+ conversation.encryption = Conversation.Encryption.PGP;
}
update_encryption_menu_icon();
}
diff --git a/qlite/src/update_builder.vala b/qlite/src/update_builder.vala
index f6729772..5f721a32 100644
--- a/qlite/src/update_builder.vala
+++ b/qlite/src/update_builder.vala
@@ -123,6 +123,7 @@ public class UpdateBuilder : StatementBuilder {
}
public void perform() throws DatabaseError {
+ if (fields == null || fields.length == 0) return;
if (prepare().step() != DONE) {
throw new DatabaseError.EXEC_ERROR(@"SQLite error: $(db.errcode()) - $(db.errmsg())");
}
diff --git a/vala-xmpp/CMakeLists.txt b/vala-xmpp/CMakeLists.txt
index 85b154da..3278d9c2 100644
--- a/vala-xmpp/CMakeLists.txt
+++ b/vala-xmpp/CMakeLists.txt
@@ -54,6 +54,7 @@ SOURCES
"src/module/xep/0049_private_xml_storage.vala"
"src/module/xep/0054_vcard/module.vala"
"src/module/xep/0060_pubsub.vala"
+ "src/module/xep/0082_date_time_profiles.vala"
"src/module/xep/0084_user_avatars.vala"
"src/module/xep/0085_chat_state_notifications.vala"
"src/module/xep/0115_entitiy_capabilities.vala"
diff --git a/vala-xmpp/src/module/xep/0082_date_time_profiles.vala b/vala-xmpp/src/module/xep/0082_date_time_profiles.vala
new file mode 100644
index 00000000..b2ce1077
--- /dev/null
+++ b/vala-xmpp/src/module/xep/0082_date_time_profiles.vala
@@ -0,0 +1,41 @@
+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);
+ }
+ return datetime;
+ }
+ return null;
+ }
+
+ public string to_datetime(DateTime time) {
+ return time.format("%Y-%m-%dT%H:%M:%SZ");
+ }
+}
+
+} \ No newline at end of file
diff --git a/vala-xmpp/src/module/xep/0203_delayed_delivery.vala b/vala-xmpp/src/module/xep/0203_delayed_delivery.vala
index 528b0017..9f9761f2 100644
--- a/vala-xmpp/src/module/xep/0203_delayed_delivery.vala
+++ b/vala-xmpp/src/module/xep/0203_delayed_delivery.vala
@@ -6,16 +6,17 @@ namespace Xmpp.Xep.DelayedDelivery {
public class Module : XmppStreamModule {
public const string ID = "0203_delayed_delivery";
+ 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));
+ message.stanza.put_node(delay_node);
+ }
+
public static DateTime? get_send_time(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 DateTime.utc(int.parse(time.substring(0, 4)),
- int.parse(time.substring(5, 2)),
- int.parse(time.substring(8, 2)),
- int.parse(time.substring(11, 2)),
- int.parse(time.substring(14, 2)),
- int.parse(time.substring(17, 2)));
+ return (new DateTimeProfiles.Module()).parse_string(time);
} else {
return null;
}
@@ -39,24 +40,15 @@ namespace Xmpp.Xep.DelayedDelivery {
public override string get_id() { return ID; }
private void on_pre_received_message(XmppStream stream, Message.Stanza message) {
- StanzaNode? delay_node = message.stanza.get_subnode("delay", NS_URI);
- if (delay_node != null) {
- string time = delay_node.get_attribute("stamp");
- DateTime datetime = new DateTime.utc(int.parse(time.substring(0, 4)),
- int.parse(time.substring(5, 2)),
- int.parse(time.substring(8, 2)),
- int.parse(time.substring(11, 2)),
- int.parse(time.substring(14, 2)),
- int.parse(time.substring(17, 2)));
- message.add_flag(new MessageFlag(datetime));
- }
+ DateTime? datetime = get_send_time(message);
+ if (datetime != null) message.add_flag(new MessageFlag(datetime));
}
}
public class MessageFlag : Message.MessageFlag {
public const string ID = "delayed_delivery";
- DateTime datetime;
+ public DateTime datetime { get; private set; }
public MessageFlag(DateTime datetime) {
this.datetime = datetime;