aboutsummaryrefslogtreecommitdiff
path: root/libdino
diff options
context:
space:
mode:
Diffstat (limited to 'libdino')
-rw-r--r--libdino/src/entity/conversation.vala21
-rw-r--r--libdino/src/entity/jid.vala2
-rw-r--r--libdino/src/entity/message.vala11
-rw-r--r--libdino/src/service/conversation_manager.vala24
-rw-r--r--libdino/src/service/database.vala11
-rw-r--r--libdino/src/service/message_manager.vala98
6 files changed, 131 insertions, 36 deletions
diff --git a/libdino/src/entity/conversation.vala b/libdino/src/entity/conversation.vala
index 55413785..5a41c7fb 100644
--- a/libdino/src/entity/conversation.vala
+++ b/libdino/src/entity/conversation.vala
@@ -6,7 +6,8 @@ public class Conversation : Object {
public enum Type {
CHAT,
- GROUPCHAT
+ GROUPCHAT,
+ GROUPCHAT_PM
}
public int id { get; set; }
@@ -30,8 +31,8 @@ public class Conversation : Object {
private Database? db;
public Conversation(Jid jid, Account account, Type type) {
- this.counterpart = jid;
this.account = account;
+ this.counterpart = jid;
this.type_ = type;
}
@@ -39,8 +40,10 @@ public class Conversation : Object {
this.db = db;
id = row[db.conversation.id];
- counterpart = new Jid(db.get_jid_by_id(row[db.conversation.jid_id]));
account = db.get_account_by_id(row[db.conversation.account_id]);
+ string? resource = row[db.conversation.resource];
+ string jid = db.get_jid_by_id(row[db.conversation.jid_id]);
+ counterpart = resource != null ? new Jid.with_resource(jid, resource) : new Jid(jid);
active = row[db.conversation.active];
int64? last_active = row[db.conversation.last_active];
if (last_active != null) this.last_active = new DateTime.from_unix_local(last_active);
@@ -55,12 +58,15 @@ public class Conversation : Object {
public void persist(Database db) {
this.db = db;
var insert = db.conversation.insert()
- .value(db.conversation.jid_id, db.get_jid_id(counterpart))
.value(db.conversation.account_id, account.id)
+ .value(db.conversation.jid_id, db.get_jid_id(counterpart))
.value(db.conversation.type_, type_)
.value(db.conversation.encryption, encryption)
//.value(conversation.read_up_to, new_conversation.read_up_to)
.value(db.conversation.active, active);
+ if (counterpart.is_full()) {
+ insert.value(db.conversation.resource, counterpart.resourcepart);
+ }
if (last_active != null) {
insert.value(db.conversation.last_active, (long) last_active.to_unix());
}
@@ -90,7 +96,12 @@ public class Conversation : Object {
case "encryption":
update.set(db.conversation.encryption, encryption); break;
case "read-up-to":
- update.set(db.conversation.read_up_to, read_up_to.id); break;
+ if (read_up_to != null) {
+ update.set(db.conversation.read_up_to, read_up_to.id);
+ } else {
+ update.set_null(db.conversation.read_up_to);
+ }
+ break;
case "active":
update.set(db.conversation.active, active); break;
case "last-active":
diff --git a/libdino/src/entity/jid.vala b/libdino/src/entity/jid.vala
index 96948ca4..edd3bc91 100644
--- a/libdino/src/entity/jid.vala
+++ b/libdino/src/entity/jid.vala
@@ -19,7 +19,7 @@ public class Dino.Entities.Jid : Object {
public Jid.with_resource(string bare_jid, string resource) {
Jid? parsed = Jid.parse(bare_jid);
- this.components(parsed.localpart, parsed.domainpart, resourcepart);
+ this.components(parsed.localpart, parsed.domainpart, resource);
}
public Jid.components(string? localpart, string domainpart, string? resourcepart) {
diff --git a/libdino/src/entity/message.vala b/libdino/src/entity/message.vala
index b5686159..4624aa87 100644
--- a/libdino/src/entity/message.vala
+++ b/libdino/src/entity/message.vala
@@ -20,8 +20,8 @@ public class Message : Object {
ERROR,
CHAT,
GROUPCHAT,
- HEADLINE,
- NORMAL
+ GROUPCHAT_PM,
+ UNKNOWN
}
public int? id { get; set; }
@@ -36,7 +36,7 @@ public class Message : Object {
}
public bool direction { get; set; }
public string? real_jid { get; set; }
- public Type type_ { get; set; }
+ public Type type_ { get; set; default = Type.UNKNOWN; }
public string? body { get; set; }
public string? stanza_id { get; set; }
public DateTime? time { get; set; }
@@ -48,10 +48,9 @@ public class Message : Object {
private Database? db;
- public Message(string? body, Type type) {
+ public Message(string? body) {
this.id = -1;
this.body = body;
- this.type_ = type;
}
public Message.from_row(Database db, Qlite.Row row) {
@@ -107,8 +106,6 @@ public class Message : Object {
type_ = Type.CHAT; break;
case Xmpp.Message.Stanza.TYPE_GROUPCHAT:
type_ = Type.GROUPCHAT; break;
- default:
- type_ = Type.NORMAL; break;
}
}
diff --git a/libdino/src/service/conversation_manager.vala b/libdino/src/service/conversation_manager.vala
index 25d355c4..ff4717ee 100644
--- a/libdino/src/service/conversation_manager.vala
+++ b/libdino/src/service/conversation_manager.vala
@@ -31,7 +31,7 @@ public class ConversationManager : StreamInteractionModule, Object {
stream_interactor.get_module(MessageManager.IDENTITY).message_sent.connect(on_message_sent);
}
- public Conversation create_conversation(Jid jid, Account account, Conversation.Type type) {
+ public Conversation create_conversation(Jid jid, Account account, Conversation.Type? type = null) {
assert(conversations.has_key(account));
if (conversations[account].has_key(jid)) {
return conversations[account][jid];
@@ -43,6 +43,26 @@ public class ConversationManager : StreamInteractionModule, Object {
}
}
+ public Conversation? get_conversation_for_message(Entities.Message message) {
+ if (message.type_ == Entities.Message.Type.CHAT) {
+ return create_conversation(message.counterpart.bare_jid, message.account, Conversation.Type.CHAT);
+ } else if (message.type_ == Entities.Message.Type.GROUPCHAT) {
+ return create_conversation(message.counterpart.bare_jid, message.account, Conversation.Type.GROUPCHAT);
+ } else if (message.type_ == Entities.Message.Type.GROUPCHAT_PM) {
+ return create_conversation(message.counterpart, message.account, Conversation.Type.GROUPCHAT_PM);
+ }
+ return null;
+ }
+
+ public Gee.List<Conversation> get_conversations_for_presence(Show show, Account account) {
+ Gee.List<Conversation> ret = new ArrayList<Conversation>(Conversation.equals_func);
+ Conversation? bare_conversation = get_conversation(show.jid, account);
+ if (bare_conversation != null) ret.add(bare_conversation);
+ Conversation? full_conversation = get_conversation(show.jid.bare_jid, account);
+ if (full_conversation != null) ret.add(full_conversation);
+ return ret;
+ }
+
public Conversation? get_conversation(Jid jid, Account account) {
if (conversations.has_key(account)) {
return conversations[account][jid];
@@ -77,7 +97,7 @@ public class ConversationManager : StreamInteractionModule, Object {
}
private void on_account_added(Account account) {
- conversations[account] = new HashMap<Jid, Conversation>(Jid.hash_bare_func, Jid.equals_bare_func);
+ conversations[account] = new HashMap<Jid, Conversation>(Jid.hash_func, Jid.equals_func);
foreach (Conversation conversation in db.get_conversations(account)) {
add_conversation(conversation);
}
diff --git a/libdino/src/service/database.vala b/libdino/src/service/database.vala
index 4115bcfa..ad12cbac 100644
--- a/libdino/src/service/database.vala
+++ b/libdino/src/service/database.vala
@@ -79,6 +79,7 @@ public class Database : Qlite.Database {
public Column<int> id = new Column.Integer("id") { primary_key = true, auto_increment = true };
public Column<int> account_id = new Column.Integer("account_id") { not_null = true };
public Column<int> jid_id = new Column.Integer("jid_id") { not_null = true };
+ public Column<string> resource = new Column.Text("resource");
public Column<bool> active = new Column.BoolInt("active");
public Column<long> last_active = new Column.Long("last_active");
public Column<int> type_ = new Column.Integer("type");
@@ -87,7 +88,7 @@ public class Database : Qlite.Database {
internal ConversationTable(Database db) {
base(db, "conversation");
- init({id, account_id, jid_id, active, last_active, type_, encryption, read_up_to});
+ init({id, account_id, jid_id, resource, active, last_active, type_, encryption, read_up_to});
}
}
@@ -164,12 +165,18 @@ public class Database : Qlite.Database {
}
}
- public Gee.List<Message> get_messages(Jid jid, Account account, int count, Message? before) {
+ public Gee.List<Message> get_messages(Jid jid, Account account, Message.Type? type, int count, Message? before) {
QueryBuilder select = message.select()
.with(message.counterpart_id, "=", get_jid_id(jid))
.with(message.account_id, "=", account.id)
.order_by(message.id, "DESC")
.limit(count);
+ if (jid.resourcepart != null) {
+ select.with(message.counterpart_resource, "=", jid.resourcepart);
+ }
+ if (type != null) {
+ select.with(message.type_, "=", (int) type);
+ }
if (before != null) {
select.with(message.time, "<", (long) before.time.to_unix());
}
diff --git a/libdino/src/service/message_manager.vala b/libdino/src/service/message_manager.vala
index 314a466b..73f49237 100644
--- a/libdino/src/service/message_manager.vala
+++ b/libdino/src/service/message_manager.vala
@@ -43,11 +43,11 @@ public class MessageManager : StreamInteractionModule, Object {
public Gee.List<Entities.Message>? get_messages(Conversation conversation, int count = 50) {
if (messages.has_key(conversation) && messages[conversation].size > 0) {
- Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, count, messages[conversation][0]);
+ Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, get_message_type_for_conversation(conversation), count, messages[conversation][0]);
db_messages.add_all(messages[conversation]);
return db_messages;
} else {
- Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, count, null);
+ Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, get_message_type_for_conversation(conversation), count, null);
return db_messages;
}
}
@@ -56,7 +56,7 @@ public class MessageManager : StreamInteractionModule, Object {
if (messages.has_key(conversation) && messages[conversation].size > 0) {
return messages[conversation][messages[conversation].size - 1];
} else {
- Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, 1, null);
+ Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, get_message_type_for_conversation(conversation), 1, null);
if (db_messages.size >= 1) {
return db_messages[0];
}
@@ -65,10 +65,22 @@ public class MessageManager : StreamInteractionModule, Object {
}
public Gee.List<Entities.Message>? get_messages_before(Conversation? conversation, Entities.Message before) {
- Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, 20, before);
+ Gee.List<Entities.Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, get_message_type_for_conversation(conversation), 20, before);
return db_messages;
}
+ private Entities.Message.Type get_message_type_for_conversation(Conversation conversation) {
+ switch (conversation.type_) {
+ case Conversation.Type.CHAT:
+ return Entities.Message.Type.CHAT;
+ case Conversation.Type.GROUPCHAT:
+ return Entities.Message.Type.GROUPCHAT;
+ case Conversation.Type.GROUPCHAT_PM:
+ return Entities.Message.Type.GROUPCHAT_PM;
+ }
+ assert_not_reached();
+ }
+
private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Xmpp.Message.Module.IDENTITY).received_message.connect( (stream, message) => {
on_message_received(account, message);
@@ -88,8 +100,15 @@ public class MessageManager : StreamInteractionModule, Object {
private void on_message_received(Account account, Xmpp.Message.Stanza message) {
if (message.body == null) return;
- Entities.Message.Type type_ = message.type_ == Xmpp.Message.Stanza.TYPE_GROUPCHAT ? Entities.Message.Type.GROUPCHAT : Entities.Message.Type.CHAT;
- Entities.Message new_message = new Entities.Message(message.body, type_);
+ Entities.Message new_message = create_in_message(account, message);
+
+ determine_message_type(account, message, new_message);
+ Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_for_message(new_message);
+ if (conversation != null) process_message(new_message, message);
+ }
+
+ private Entities.Message create_in_message(Account account, Xmpp.Message.Stanza message) {
+ Entities.Message new_message = new Entities.Message(message.body);
new_message.account = account;
new_message.stanza_id = message.id;
Jid from_jid = new Jid(message.from);
@@ -105,18 +124,59 @@ public class MessageManager : StreamInteractionModule, Object {
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_local();
new_message.local_time = new DateTime.now_local();
- Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(new_message.counterpart, account, Conversation.Type.CHAT);
- pre_message_received(new_message, message, conversation);
-
- bool is_uuid = new_message.stanza_id != null && Regex.match_simple("""[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}""", new_message.stanza_id);
- if ((is_uuid && !db.contains_message_by_stanza_id(new_message.stanza_id, conversation.account)) ||
- (!is_uuid && !db.contains_message(new_message, conversation.account))) {
- new_message.persist(db);
- add_message(new_message, conversation);
- if (new_message.direction == Entities.Message.DIRECTION_SENT) {
- message_sent(new_message, conversation);
+ return new_message;
+ }
+
+ private void process_message(Entities.Message new_message, Xmpp.Message.Stanza stanza) {
+ Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_for_message(new_message);
+ if (conversation != null) {
+ pre_message_received(new_message, stanza, conversation);
+
+ bool is_uuid = new_message.stanza_id != null && Regex.match_simple("""[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}""", new_message.stanza_id);
+ if ((is_uuid && !db.contains_message_by_stanza_id(new_message.stanza_id, conversation.account)) ||
+ (!is_uuid && !db.contains_message(new_message, conversation.account))) {
+ new_message.persist(db);
+ add_message(new_message, conversation);
+ if (new_message.direction == Entities.Message.DIRECTION_SENT) {
+ message_sent(new_message, conversation);
+ } else {
+ message_received(new_message, conversation);
+ }
+ }
+ }
+ }
+
+ private void determine_message_type(Account account, Xmpp.Message.Stanza message_stanza, Entities.Message message) {
+ if (message_stanza.type_ == Xmpp.Message.Stanza.TYPE_GROUPCHAT) {
+ message.type_ = Entities.Message.Type.GROUPCHAT;
+ process_message(message, message_stanza);
+ } else if (message_stanza.type_ == Xmpp.Message.Stanza.TYPE_CHAT) {
+ Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(message.counterpart.bare_jid, account);
+ if (conversation != null) {
+ if (conversation.type_ == Conversation.Type.CHAT) {
+ message.type_ = Entities.Message.Type.CHAT;
+ } else if (conversation.type_ == Conversation.Type.GROUPCHAT) {
+ message.type_ = Entities.Message.Type.GROUPCHAT_PM;
+ }
} else {
- message_received(new_message, conversation);
+ Core.XmppStream stream = stream_interactor.get_stream(account);
+ if (stream != null) stream.get_module(Xep.ServiceDiscovery.Module.IDENTITY).get_entity_categories(stream, message.counterpart.bare_jid.to_string(), (stream, identities, store) => {
+ Triple<MessageManager, Entities.Message, Xmpp.Message.Stanza> triple = store as Triple<MessageManager, Entities.Message, Xmpp.Message.Stanza>;
+ Entities.Message m = triple.b;
+ if (identities == null) {
+ m.type_ = Entities.Message.Type.CHAT;
+ triple.a.process_message(m, triple.c);
+ return;
+ }
+ foreach (Xep.ServiceDiscovery.Identity identity in identities) {
+ if (identity.category == Xep.ServiceDiscovery.Identity.CATEGORY_CONFERENCE) {
+ m.type_ = Entities.Message.Type.GROUPCHAT_PM;
+ } else {
+ m.type_ = Entities.Message.Type.CHAT;
+ }
+ triple.a.process_message(m, triple.c);
+ }
+ }, Triple.create(this, message, message_stanza));
}
}
}
@@ -129,8 +189,8 @@ public class MessageManager : StreamInteractionModule, Object {
}
private Entities.Message create_out_message(string text, Conversation conversation) {
- Entities.Message.Type type_ = conversation.type_ == Conversation.Type.GROUPCHAT ? Entities.Message.Type.GROUPCHAT : Entities.Message.Type.CHAT;
- Entities.Message message = new Entities.Message(text, type_);
+ Entities.Message message = new Entities.Message(text);
+ message.type_ = get_message_type_for_conversation(conversation);
message.stanza_id = random_uuid();
message.account = conversation.account;
message.body = text;