Save unsent messages (acc offline etc) and send later; don't send pgp messages if pgp error
This commit is contained in:
parent
b1e6e51c4f
commit
5fc0435cc1
|
@ -3,19 +3,23 @@ public class Conversation : Object {
|
||||||
|
|
||||||
public signal void object_updated(Conversation conversation);
|
public signal void object_updated(Conversation conversation);
|
||||||
|
|
||||||
public const int ENCRYPTION_UNENCRYPTED = 0;
|
public enum Encryption {
|
||||||
public const int ENCRYPTION_PGP = 1;
|
UNENCRYPTED,
|
||||||
|
PGP
|
||||||
|
}
|
||||||
|
|
||||||
public const int TYPE_CHAT = 0;
|
public enum Type {
|
||||||
public const int TYPE_GROUPCHAT = 1;
|
CHAT,
|
||||||
|
GROUPCHAT
|
||||||
|
}
|
||||||
|
|
||||||
public int id { get; set; }
|
public int id { get; set; }
|
||||||
public Account account { get; private set; }
|
public Account account { get; private set; }
|
||||||
public Jid counterpart { get; private set; }
|
public Jid counterpart { get; private set; }
|
||||||
public bool active { get; set; }
|
public bool active { get; set; }
|
||||||
public DateTime last_active { get; set; }
|
public DateTime last_active { get; set; }
|
||||||
public int encryption { get; set; }
|
public Encryption encryption { get; set; }
|
||||||
public int? type_ { get; set; }
|
public Type? type_ { get; set; }
|
||||||
public Message read_up_to { get; set; }
|
public Message read_up_to { get; set; }
|
||||||
|
|
||||||
public Conversation(Jid jid, Account account) {
|
public Conversation(Jid jid, Account account) {
|
||||||
|
@ -23,7 +27,7 @@ public class Conversation : Object {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.last_active = new DateTime.from_unix_utc(0);
|
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) {
|
public Conversation.with_id(Jid jid, Account account, int id) {
|
||||||
|
|
|
@ -11,7 +11,9 @@ public class Dino.Entities.Message : Object {
|
||||||
NONE,
|
NONE,
|
||||||
RECEIVED,
|
RECEIVED,
|
||||||
READ,
|
READ,
|
||||||
ACKNOWLEDGED
|
ACKNOWLEDGED,
|
||||||
|
UNSENT,
|
||||||
|
WONTSEND
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Encryption {
|
public enum Encryption {
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
|
||||||
|
|
||||||
public void on_message_entered(Conversation conversation) {
|
public void on_message_entered(Conversation conversation) {
|
||||||
if (Settings.instance().send_read) {
|
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);
|
send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_COMPOSING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void check_send_read() {
|
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);
|
Entities.Message? message = MessageManager.get_instance(stream_interactor).get_last_message(selected_conversation);
|
||||||
if (message != null && message.direction == Entities.Message.DIRECTION_RECEIVED &&
|
if (message != null && message.direction == Entities.Message.DIRECTION_RECEIVED &&
|
||||||
message.stanza != null && !message.equals(selected_conversation.read_up_to)) {
|
message.stanza != null && !message.equals(selected_conversation.read_up_to)) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ public class ConversationManager : StreamInteractionModule, Object {
|
||||||
stream_interactor.account_added.connect(on_account_added);
|
stream_interactor.account_added.connect(on_account_added);
|
||||||
MucManager.get_instance(stream_interactor).groupchat_joined.connect(on_groupchat_joined);
|
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).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) {
|
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) {
|
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);
|
return get_conversation(jid, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ensure_start_conversation(Jid jid, Account 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);
|
Conversation? conversation = get_conversation(jid, account);
|
||||||
if (conversation != null) {
|
if (conversation != null) {
|
||||||
conversation.last_active = new DateTime.now_utc();
|
conversation.last_active = new DateTime.now_utc();
|
||||||
|
@ -73,12 +74,16 @@ public class ConversationManager : StreamInteractionModule, Object {
|
||||||
ensure_start_conversation(conversation.counterpart, conversation.account);
|
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) {
|
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);
|
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)) {
|
if (conversations.has_key(account) && !conversations[account].has_key(jid)) {
|
||||||
Conversation conversation = new Conversation(jid, account);
|
Conversation conversation = new Conversation(jid, account);
|
||||||
conversation.type_ = type;
|
conversation.type_ = type;
|
||||||
|
|
|
@ -36,11 +36,11 @@ public class Database : Qlite.Database {
|
||||||
public class MessageTable : Table {
|
public class MessageTable : Table {
|
||||||
public Column<int> id = new Column.Integer("id") { primary_key = true, auto_increment = true };
|
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<string> stanza_id = new Column.Text("stanza_id");
|
||||||
public Column<int> account_id = new Column.Integer("account_id");
|
public Column<int> account_id = new Column.Integer("account_id") { not_null = true };
|
||||||
public Column<int> counterpart_id = new Column.Integer("counterpart_id");
|
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> counterpart_resource = new Column.Text("counterpart_resource");
|
||||||
public Column<string> our_resource = new Column.Text("our_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<int> type_ = new Column.Integer("type");
|
||||||
public Column<long> time = new Column.Long("time");
|
public Column<long> time = new Column.Long("time");
|
||||||
public Column<long> local_time = new Column.Long("local_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) {
|
public void add_message(Message new_message, Account account) {
|
||||||
if (new_message.body == null || new_message.stanza_id == null) {
|
InsertBuilder builder = message.insert()
|
||||||
return;
|
.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)
|
||||||
new_message.id = (int) message.insert()
|
.value(message.our_resource, new_message.ourpart.resourcepart)
|
||||||
.value(message.stanza_id, new_message.stanza_id)
|
.value(message.direction, new_message.direction)
|
||||||
.value(message.account_id, new_message.account.id)
|
.value(message.type_, new_message.type_)
|
||||||
.value(message.counterpart_id, get_jid_id(new_message.counterpart))
|
.value(message.time, (long) new_message.time.to_unix())
|
||||||
.value(message.counterpart_resource, new_message.counterpart.resourcepart)
|
.value(message.local_time, (long) new_message.local_time.to_unix())
|
||||||
.value(message.our_resource, new_message.ourpart.resourcepart)
|
.value(message.body, new_message.body)
|
||||||
.value(message.direction, new_message.direction)
|
.value(message.encryption, new_message.encryption)
|
||||||
.value(message.type_, new_message.type_)
|
.value(message.marked, new_message.marked);
|
||||||
.value(message.time, (long) new_message.time.to_unix())
|
if (new_message.stanza_id != null) builder.value(message.stanza_id, new_message.stanza_id);
|
||||||
.value(message.local_time, (long) new_message.local_time.to_unix())
|
new_message.id = (int) builder.perform();
|
||||||
.value(message.body, new_message.body)
|
|
||||||
.value(message.encryption, new_message.encryption)
|
|
||||||
.value(message.marked, new_message.marked)
|
|
||||||
.perform();
|
|
||||||
|
|
||||||
if (new_message.real_jid != null) {
|
if (new_message.real_jid != null) {
|
||||||
real_jid.insert()
|
real_jid.insert()
|
||||||
|
@ -288,6 +284,14 @@ public class Database : Qlite.Database {
|
||||||
return ret;
|
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) {
|
public bool contains_message(Message query_message, Account account) {
|
||||||
int jid_id = get_jid_id(query_message.counterpart);
|
int jid_id = get_jid_id(query_message.counterpart);
|
||||||
return message.select()
|
return message.select()
|
||||||
|
@ -295,6 +299,9 @@ public class Database : Qlite.Database {
|
||||||
.with(message.stanza_id, "=", query_message.stanza_id)
|
.with(message.stanza_id, "=", query_message.stanza_id)
|
||||||
.with(message.counterpart_id, "=", jid_id)
|
.with(message.counterpart_id, "=", jid_id)
|
||||||
.with(message.counterpart_resource, "=", query_message.counterpart.resourcepart)
|
.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;
|
.count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +339,8 @@ public class Database : Qlite.Database {
|
||||||
new_message.marked = (Message.Marked) row[message.marked];
|
new_message.marked = (Message.Marked) row[message.marked];
|
||||||
new_message.encryption = (Message.Encryption) row[message.encryption];
|
new_message.encryption = (Message.Encryption) row[message.encryption];
|
||||||
new_message.real_jid = get_real_jid_for_message(new_message);
|
new_message.real_jid = get_real_jid_for_message(new_message);
|
||||||
|
|
||||||
|
new_message.notify.connect(on_message_update);
|
||||||
return new_message;
|
return new_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,8 +395,8 @@ public class Database : Qlite.Database {
|
||||||
new_conversation.active = row[conversation.active];
|
new_conversation.active = row[conversation.active];
|
||||||
int64? last_active = row[conversation.last_active];
|
int64? last_active = row[conversation.last_active];
|
||||||
if (last_active != null) new_conversation.last_active = new DateTime.from_unix_utc(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.type_ = (Conversation.Type) row[conversation.type_];
|
||||||
new_conversation.encryption = row[conversation.encryption];
|
new_conversation.encryption = (Conversation.Encryption) row[conversation.encryption];
|
||||||
int? read_up_to = row[conversation.read_up_to];
|
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);
|
if (read_up_to != null) new_conversation.read_up_to = get_message_by_id(read_up_to);
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ using Dino.Entities;
|
||||||
namespace Dino {
|
namespace Dino {
|
||||||
|
|
||||||
public class MessageManager : StreamInteractionModule, Object {
|
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 pre_message_received(Entities.Message message, Conversation conversation);
|
||||||
public signal void 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.stream_interactor = stream_interactor;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
stream_interactor.account_added.connect(on_account_added);
|
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) {
|
public void send_message(string text, Conversation conversation) {
|
||||||
Entities.Message message = new Entities.Message();
|
Entities.Message message = create_out_message(text, conversation);
|
||||||
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;
|
|
||||||
add_message(message, conversation);
|
add_message(message, conversation);
|
||||||
|
db.add_message(message, conversation.account);
|
||||||
|
send_xmpp_message(message, conversation);
|
||||||
message_sent(message, conversation);
|
message_sent(message, conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,17 +67,26 @@ public class MessageManager : StreamInteractionModule, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public string get_id() {
|
public string get_id() {
|
||||||
return id;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MessageManager? get_instance(StreamInteractor stream_interactor) {
|
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) {
|
private void on_account_added(Account account) {
|
||||||
stream_interactor.module_manager.message_modules[account].received_message.connect( (stream, message) => {
|
stream_interactor.module_manager.message_modules[account].received_message.connect( (stream, message) => {
|
||||||
on_message_received(account, 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) {
|
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.body = message.body;
|
||||||
new_message.stanza = message;
|
new_message.stanza = message;
|
||||||
new_message.set_type_string(message.type_);
|
new_message.set_type_string(message.type_);
|
||||||
new_message.time = Xep.DelayedDelivery.Module.get_send_time(message);
|
Xep.DelayedDelivery.MessageFlag? deleyed_delivery_flag = Xep.DelayedDelivery.MessageFlag.get_flag(message);
|
||||||
if (new_message.time == null) {
|
new_message.time = deleyed_delivery_flag != null ? deleyed_delivery_flag.datetime : new DateTime.now_utc();
|
||||||
new_message.time = new DateTime.now_utc();
|
|
||||||
}
|
|
||||||
new_message.local_time = new DateTime.now_utc();
|
new_message.local_time = new DateTime.now_utc();
|
||||||
if (Xep.Pgp.MessageFlag.get_flag(message) != null) {
|
if (Xep.Pgp.MessageFlag.get_flag(message) != null) {
|
||||||
new_message.encryption = Entities.Message.Encryption.PGP;
|
new_message.encryption = Entities.Message.Encryption.PGP;
|
||||||
|
@ -161,6 +138,56 @@ public class MessageManager : StreamInteractionModule, Object {
|
||||||
}
|
}
|
||||||
messages[conversation].add(message);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -66,7 +66,7 @@ public class MucManager : StreamInteractionModule, Object {
|
||||||
|
|
||||||
public bool is_groupchat(Jid jid, Account account) {
|
public bool is_groupchat(Jid jid, Account account) {
|
||||||
Conversation? conversation = ConversationManager.get_instance(stream_interactor).get_conversation(jid, 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) {
|
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) {
|
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);
|
Core.XmppStream stream = stream_interactor.get_stream(conversation.account);
|
||||||
if (stream == null) return;
|
if (stream == null) return;
|
||||||
if (Xep.DelayedDelivery.MessageFlag.get_flag(message.stanza) == null) {
|
if (Xep.DelayedDelivery.MessageFlag.get_flag(message.stanza) == null) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Xmpp;
|
||||||
using Dino.Entities;
|
using Dino.Entities;
|
||||||
|
|
||||||
namespace Dino {
|
namespace Dino {
|
||||||
|
|
||||||
public class StreamInteractor {
|
public class StreamInteractor {
|
||||||
|
|
||||||
public signal void account_added(Account account);
|
public signal void account_added(Account account);
|
||||||
|
@ -65,4 +66,5 @@ public class StreamInteractor {
|
||||||
public interface StreamInteractionModule : Object {
|
public interface StreamInteractionModule : Object {
|
||||||
internal abstract string get_id();
|
internal abstract string get_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -95,7 +95,7 @@ public class List : ListBox {
|
||||||
public void add_conversation(Conversation conversation) {
|
public void add_conversation(Conversation conversation) {
|
||||||
ConversationRow row;
|
ConversationRow row;
|
||||||
if (!rows.has_key(conversation)) {
|
if (!rows.has_key(conversation)) {
|
||||||
if (conversation.type_ == Conversation.TYPE_GROUPCHAT) {
|
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
||||||
row = new GroupchatRow(stream_interactor, conversation);
|
row = new GroupchatRow(stream_interactor, conversation);
|
||||||
} else {
|
} else {
|
||||||
row = new ChatRow(stream_interactor, conversation);
|
row = new ChatRow(stream_interactor, conversation);
|
||||||
|
|
|
@ -68,10 +68,16 @@ public class MergedMessageItem : Grid {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update_received() {
|
private void update_received() {
|
||||||
|
received_image.visible = true;
|
||||||
bool all_received = true;
|
bool all_received = true;
|
||||||
bool all_read = true;
|
bool all_read = true;
|
||||||
foreach (Message message in messages) {
|
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;
|
all_read = false;
|
||||||
if (message.marked != Message.Marked.RECEIVED) {
|
if (message.marked != Message.Marked.RECEIVED) {
|
||||||
all_received = false;
|
all_received = false;
|
||||||
|
|
|
@ -203,7 +203,8 @@ public class View : Box {
|
||||||
return message_item != null &&
|
return message_item != null &&
|
||||||
message_item.from.equals(message.from) &&
|
message_item.from.equals(message.from) &&
|
||||||
message_item.messages.get(0).encryption == message.encryption &&
|
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) {
|
private void force_alloc_width(Widget widget, int width) {
|
||||||
|
|
|
@ -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);
|
string? pgp_id = PgpManager.get_instance(stream_interactor).get_key_id(conversation.account, conversation.counterpart);
|
||||||
button_pgp.set_sensitive(pgp_id != null);
|
button_pgp.set_sensitive(pgp_id != null);
|
||||||
switch (conversation.encryption) {
|
switch (conversation.encryption) {
|
||||||
case Conversation.ENCRYPTION_UNENCRYPTED:
|
case Conversation.Encryption.UNENCRYPTED:
|
||||||
button_unencrypted.set_active(true);
|
button_unencrypted.set_active(true);
|
||||||
break;
|
break;
|
||||||
case Conversation.ENCRYPTION_PGP:
|
case Conversation.Encryption.PGP:
|
||||||
button_pgp.set_active(true);
|
button_pgp.set_active(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update_encryption_menu_icon() {
|
private void update_encryption_menu_icon() {
|
||||||
encryption_button.visible = conversation.type_ == Conversation.TYPE_CHAT;
|
encryption_button.visible = (conversation.type_ == Conversation.Type.CHAT);
|
||||||
if (conversation.type_ == Conversation.TYPE_CHAT) {
|
if (conversation.type_ == Conversation.Type.CHAT) {
|
||||||
if (conversation.encryption == Conversation.ENCRYPTION_UNENCRYPTED) {
|
if (conversation.encryption == Conversation.Encryption.UNENCRYPTED) {
|
||||||
encryption_button.set_image(new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON));
|
encryption_button.set_image(new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON));
|
||||||
} else {
|
} else {
|
||||||
encryption_button.set_image(new Image.from_icon_name("changes-prevent-symbolic", IconSize.BUTTON));
|
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() {
|
private void update_groupchat_menu() {
|
||||||
groupchat_button.visible = conversation.type_ == Conversation.TYPE_GROUPCHAT;
|
groupchat_button.visible = conversation.type_ == Conversation.Type.GROUPCHAT;
|
||||||
if (conversation.type_ == Conversation.TYPE_GROUPCHAT) {
|
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
||||||
groupchat_button.set_use_popover(true);
|
groupchat_button.set_use_popover(true);
|
||||||
Popover popover = new Popover(null);
|
Popover popover = new Popover(null);
|
||||||
OccupantList occupant_list = new OccupantList(stream_interactor, conversation);
|
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) {
|
private void update_subtitle(string? subtitle = null) {
|
||||||
if (subtitle != null) {
|
if (subtitle != null) {
|
||||||
set_subtitle(subtitle);
|
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);
|
string subject = MucManager.get_instance(stream_interactor).get_groupchat_subject(conversation.counterpart, conversation.account);
|
||||||
set_subtitle(subject != "" ? subject : null);
|
set_subtitle(subject != "" ? subject : null);
|
||||||
} else {
|
} else {
|
||||||
|
@ -106,9 +106,9 @@ public class Dino.Ui.ConversationTitlebar : Gtk.HeaderBar {
|
||||||
button_unencrypted.toggled.connect(() => {
|
button_unencrypted.toggled.connect(() => {
|
||||||
if (conversation != null) {
|
if (conversation != null) {
|
||||||
if (button_unencrypted.get_active()) {
|
if (button_unencrypted.get_active()) {
|
||||||
conversation.encryption = Conversation.ENCRYPTION_UNENCRYPTED;
|
conversation.encryption = Conversation.Encryption.UNENCRYPTED;
|
||||||
} else if (button_pgp.get_active()) {
|
} else if (button_pgp.get_active()) {
|
||||||
conversation.encryption = Conversation.ENCRYPTION_PGP;
|
conversation.encryption = Conversation.Encryption.PGP;
|
||||||
}
|
}
|
||||||
update_encryption_menu_icon();
|
update_encryption_menu_icon();
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,7 @@ public class UpdateBuilder : StatementBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void perform() throws DatabaseError {
|
public void perform() throws DatabaseError {
|
||||||
|
if (fields == null || fields.length == 0) return;
|
||||||
if (prepare().step() != DONE) {
|
if (prepare().step() != DONE) {
|
||||||
throw new DatabaseError.EXEC_ERROR(@"SQLite error: $(db.errcode()) - $(db.errmsg())");
|
throw new DatabaseError.EXEC_ERROR(@"SQLite error: $(db.errcode()) - $(db.errmsg())");
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ SOURCES
|
||||||
"src/module/xep/0049_private_xml_storage.vala"
|
"src/module/xep/0049_private_xml_storage.vala"
|
||||||
"src/module/xep/0054_vcard/module.vala"
|
"src/module/xep/0054_vcard/module.vala"
|
||||||
"src/module/xep/0060_pubsub.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/0084_user_avatars.vala"
|
||||||
"src/module/xep/0085_chat_state_notifications.vala"
|
"src/module/xep/0085_chat_state_notifications.vala"
|
||||||
"src/module/xep/0115_entitiy_capabilities.vala"
|
"src/module/xep/0115_entitiy_capabilities.vala"
|
||||||
|
|
41
vala-xmpp/src/module/xep/0082_date_time_profiles.vala
Normal file
41
vala-xmpp/src/module/xep/0082_date_time_profiles.vala
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,16 +6,17 @@ namespace Xmpp.Xep.DelayedDelivery {
|
||||||
public class Module : XmppStreamModule {
|
public class Module : XmppStreamModule {
|
||||||
public const string ID = "0203_delayed_delivery";
|
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) {
|
public static DateTime? get_send_time(Message.Stanza message) {
|
||||||
StanzaNode? delay_node = message.stanza.get_subnode("delay", NS_URI);
|
StanzaNode? delay_node = message.stanza.get_subnode("delay", NS_URI);
|
||||||
if (delay_node != null) {
|
if (delay_node != null) {
|
||||||
string time = delay_node.get_attribute("stamp");
|
string time = delay_node.get_attribute("stamp");
|
||||||
return new DateTime.utc(int.parse(time.substring(0, 4)),
|
return (new DateTimeProfiles.Module()).parse_string(time);
|
||||||
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)));
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -39,24 +40,15 @@ namespace Xmpp.Xep.DelayedDelivery {
|
||||||
public override string get_id() { return ID; }
|
public override string get_id() { return ID; }
|
||||||
|
|
||||||
private void on_pre_received_message(XmppStream stream, Message.Stanza message) {
|
private void on_pre_received_message(XmppStream stream, Message.Stanza message) {
|
||||||
StanzaNode? delay_node = message.stanza.get_subnode("delay", NS_URI);
|
DateTime? datetime = get_send_time(message);
|
||||||
if (delay_node != null) {
|
if (datetime != null) message.add_flag(new MessageFlag(datetime));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MessageFlag : Message.MessageFlag {
|
public class MessageFlag : Message.MessageFlag {
|
||||||
public const string ID = "delayed_delivery";
|
public const string ID = "delayed_delivery";
|
||||||
|
|
||||||
DateTime datetime;
|
public DateTime datetime { get; private set; }
|
||||||
|
|
||||||
public MessageFlag(DateTime datetime) {
|
public MessageFlag(DateTime datetime) {
|
||||||
this.datetime = datetime;
|
this.datetime = datetime;
|
||||||
|
|
Loading…
Reference in a new issue