Move Jid class to xmpp-vala, partially refactor namespace

This commit is contained in:
Marvin W 2018-01-12 21:03:09 +01:00 committed by fiaxh
parent d46d071e57
commit 782ae4c049
116 changed files with 925 additions and 961 deletions

View file

@ -17,7 +17,6 @@ SOURCES
src/entity/conversation.vala src/entity/conversation.vala
src/entity/encryption.vala src/entity/encryption.vala
src/entity/file_transfer.vala src/entity/file_transfer.vala
src/entity/jid.vala
src/entity/message.vala src/entity/message.vala
src/entity/settings.vala src/entity/settings.vala

View file

@ -1,4 +1,5 @@
using Gee; using Gee;
using Xmpp;
namespace Dino.Entities { namespace Dino.Entities {

View file

@ -1,3 +1,5 @@
using Xmpp;
namespace Dino.Entities { namespace Dino.Entities {
public class Conversation : Object { public class Conversation : Object {
@ -11,6 +13,7 @@ public class Conversation : Object {
} }
public int id { get; set; } public int id { get; set; }
public Type type_ { 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; default = false; } public bool active { get; set; default = false; }
@ -25,7 +28,6 @@ public class Conversation : Object {
} }
} }
public Encryption encryption { get; set; default = Encryption.NONE; } public Encryption encryption { get; set; default = Encryption.NONE; }
public Type type_ { get; set; }
public Message? read_up_to { get; set; } public Message? read_up_to { get; set; }
public enum NotifySetting { DEFAULT, ON, OFF, HIGHLIGHT } public enum NotifySetting { DEFAULT, ON, OFF, HIGHLIGHT }
@ -48,14 +50,14 @@ public class Conversation : Object {
this.db = db; this.db = db;
id = row[db.conversation.id]; id = row[db.conversation.id];
type_ = (Conversation.Type) row[db.conversation.type_];
account = db.get_account_by_id(row[db.conversation.account_id]); account = db.get_account_by_id(row[db.conversation.account_id]);
string? resource = row[db.conversation.resource]; string? resource = row[db.conversation.resource];
string jid = db.get_jid_by_id(row[db.conversation.jid_id]); counterpart = Jid.parse(db.get_jid_by_id(row[db.conversation.jid_id]));
counterpart = resource != null ? new Jid.with_resource(jid, resource) : new Jid(jid); if (type_ == Conversation.Type.GROUPCHAT_PM) counterpart = counterpart.with_resource(resource);
active = row[db.conversation.active]; active = row[db.conversation.active];
int64? last_active = row[db.conversation.last_active]; int64? last_active = row[db.conversation.last_active];
if (last_active != null) this.last_active = new DateTime.from_unix_utc(last_active); if (last_active != null) this.last_active = new DateTime.from_unix_utc(last_active);
type_ = (Conversation.Type) row[db.conversation.type_];
encryption = (Encryption) row[db.conversation.encryption]; encryption = (Encryption) row[db.conversation.encryption];
int? read_up_to = row[db.conversation.read_up_to]; int? read_up_to = row[db.conversation.read_up_to];
if (read_up_to != null) this.read_up_to = db.get_message_by_id(read_up_to); if (read_up_to != null) this.read_up_to = db.get_message_by_id(read_up_to);
@ -95,10 +97,10 @@ public class Conversation : Object {
} }
public NotifySetting get_notification_default_setting(StreamInteractor stream_interactor) { public NotifySetting get_notification_default_setting(StreamInteractor stream_interactor) {
Xmpp.Core.XmppStream? stream = stream_interactor.get_stream(account); Xmpp.XmppStream? stream = stream_interactor.get_stream(account);
if (!Application.get_default().settings.notifications) return NotifySetting.OFF; if (!Application.get_default().settings.notifications) return NotifySetting.OFF;
if (type_ == Type.GROUPCHAT) { if (type_ == Type.GROUPCHAT) {
bool members_only = stream.get_flag(Xmpp.Xep.Muc.Flag.IDENTITY).has_room_feature(counterpart.bare_jid.to_string(), Xmpp.Xep.Muc.Feature.MEMBERS_ONLY); bool members_only = stream.get_flag(Xmpp.Xep.Muc.Flag.IDENTITY).has_room_feature(counterpart.bare_jid, Xmpp.Xep.Muc.Feature.MEMBERS_ONLY);
return members_only ? NotifySetting.ON : NotifySetting.HIGHLIGHT; return members_only ? NotifySetting.ON : NotifySetting.HIGHLIGHT;
} }
return NotifySetting.ON; return NotifySetting.ON;

View file

@ -1,3 +1,5 @@
using Xmpp;
namespace Dino.Entities { namespace Dino.Entities {
public class FileTransfer : Object { public class FileTransfer : Object {
@ -48,11 +50,12 @@ public class FileTransfer : Object {
string counterpart_jid = db.get_jid_by_id(row[db.file_transfer.counterpart_id]); string counterpart_jid = db.get_jid_by_id(row[db.file_transfer.counterpart_id]);
string counterpart_resource = row[db.file_transfer.counterpart_resource]; string counterpart_resource = row[db.file_transfer.counterpart_resource];
counterpart = counterpart_resource != null ? new Jid.with_resource(counterpart_jid, counterpart_resource) : new Jid(counterpart_jid); counterpart = Jid.parse(counterpart_jid);
if (counterpart_resource != null) counterpart = counterpart.with_resource(counterpart_resource);
string our_resource = row[db.file_transfer.our_resource]; string our_resource = row[db.file_transfer.our_resource];
if (our_resource != null) { if (our_resource != null) {
ourpart = new Jid.with_resource(account.bare_jid.to_string(), our_resource); ourpart = account.bare_jid.with_resource(our_resource);
} else { } else {
ourpart = account.bare_jid; ourpart = account.bare_jid;
} }

View file

@ -1,4 +1,5 @@
using Gee; using Gee;
using Xmpp;
namespace Dino.Entities { namespace Dino.Entities {
@ -51,7 +52,7 @@ public class Message : Object {
marked_ = value; marked_ = value;
} }
} }
public Xmpp.Message.Stanza stanza { get; set; } public Xmpp.MessageStanza stanza { get; set; }
private Database? db; private Database? db;
@ -67,15 +68,15 @@ public class Message : Object {
stanza_id = row[db.message.stanza_id]; stanza_id = row[db.message.stanza_id];
type_ = (Message.Type) row[db.message.type_]; type_ = (Message.Type) row[db.message.type_];
string counterpart_jid = db.get_jid_by_id(row[db.message.counterpart_id]); counterpart = Jid.parse(db.get_jid_by_id(row[db.message.counterpart_id]));
string counterpart_resource = row[db.message.counterpart_resource]; string counterpart_resource = row[db.message.counterpart_resource];
counterpart = counterpart_resource != null ? new Jid.with_resource(counterpart_jid, counterpart_resource) : new Jid(counterpart_jid); if (counterpart_resource != null) counterpart = counterpart.with_resource(counterpart_resource);
string our_resource = row[db.message.our_resource]; string our_resource = row[db.message.our_resource];
if (type_ == Type.GROUPCHAT && our_resource != null) { if (type_ == Type.GROUPCHAT && our_resource != null) {
ourpart = new Jid.with_resource(counterpart_jid, our_resource); ourpart = counterpart.with_resource(our_resource);
} else if (our_resource != null) { } else if (our_resource != null) {
ourpart = new Jid.with_resource(account.bare_jid.to_string(), our_resource); ourpart = account.bare_jid.with_resource(our_resource);
} else { } else {
ourpart = account.bare_jid; ourpart = account.bare_jid;
} }
@ -121,9 +122,9 @@ public class Message : Object {
public void set_type_string(string type) { public void set_type_string(string type) {
switch (type) { switch (type) {
case Xmpp.Message.Stanza.TYPE_CHAT: case Xmpp.MessageStanza.TYPE_CHAT:
type_ = Type.CHAT; break; type_ = Type.CHAT; break;
case Xmpp.Message.Stanza.TYPE_GROUPCHAT: case Xmpp.MessageStanza.TYPE_GROUPCHAT:
type_ = Type.GROUPCHAT; break; type_ = Type.GROUPCHAT; break;
} }
} }
@ -131,11 +132,11 @@ public class Message : Object {
public new string get_type_string() { public new string get_type_string() {
switch (type_) { switch (type_) {
case Type.CHAT: case Type.CHAT:
return Xmpp.Message.Stanza.TYPE_CHAT; return Xmpp.MessageStanza.TYPE_CHAT;
case Type.GROUPCHAT: case Type.GROUPCHAT:
return Xmpp.Message.Stanza.TYPE_GROUPCHAT; return Xmpp.MessageStanza.TYPE_GROUPCHAT;
default: default:
return Xmpp.Message.Stanza.TYPE_NORMAL; return Xmpp.MessageStanza.TYPE_NORMAL;
} }
} }

View file

@ -1,4 +1,5 @@
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Plugins { namespace Dino.Plugins {

View file

@ -41,22 +41,18 @@ public class AvatarManager : StreamInteractionModule, Object {
stream_interactor.module_manager.initialize_account_modules.connect(initialize_avatar_modules); stream_interactor.module_manager.initialize_account_modules.connect(initialize_avatar_modules);
} }
private void initialize_avatar_modules(Account account, ArrayList<Core.XmppStreamModule> modules) { private void initialize_avatar_modules(Account account, ArrayList<XmppStreamModule> modules) {
modules.add(new Xep.UserAvatars.Module(avatar_storage)); modules.add(new Xep.UserAvatars.Module(avatar_storage));
modules.add(new Xep.VCard.Module(avatar_storage)); modules.add(new Xep.VCard.Module(avatar_storage));
} }
private Pixbuf? get_avatar_by_hash(string hash) { private Pixbuf? get_avatar_by_hash(string hash) {
lock (cached_pixbuf) { if (cached_pixbuf.has_key(hash)) {
if (cached_pixbuf.has_key(hash)) { return cached_pixbuf[hash];
return cached_pixbuf[hash];
}
} }
Pixbuf? image = avatar_storage.get_image(hash); Pixbuf? image = avatar_storage.get_image(hash);
if (image != null) { if (image != null) {
lock (cached_pixbuf) { cached_pixbuf[hash] = image;
cached_pixbuf[hash] = image;
}
} }
return image; return image;
} }
@ -66,17 +62,13 @@ public class AvatarManager : StreamInteractionModule, Object {
if (!stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account)) { if (!stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account)) {
jid_ = jid.bare_jid; jid_ = jid.bare_jid;
} }
lock(user_avatars) { string? user_avatars_id = user_avatars[jid_];
string? user_avatars_id = user_avatars[jid_]; if (user_avatars_id != null) {
if (user_avatars_id != null) { return get_avatar_by_hash(user_avatars_id);
return get_avatar_by_hash(user_avatars_id);
}
} }
lock(vcard_avatars) { string? vcard_avatars_id = vcard_avatars[jid_];
string? vcard_avatars_id = vcard_avatars[jid_]; if (vcard_avatars_id != null) {
if (vcard_avatars_id != null) { return get_avatar_by_hash(vcard_avatars_id);
return get_avatar_by_hash(vcard_avatars_id);
}
} }
return null; return null;
} }
@ -93,7 +85,7 @@ public class AvatarManager : StreamInteractionModule, Object {
} }
uint8[] buffer; uint8[] buffer;
pixbuf.save_to_buffer(out buffer, "png"); pixbuf.save_to_buffer(out buffer, "png");
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
stream.get_module(Xep.UserAvatars.Module.IDENTITY).publish_png(stream, buffer, pixbuf.width, pixbuf.height); stream.get_module(Xep.UserAvatars.Module.IDENTITY).publish_png(stream, buffer, pixbuf.width, pixbuf.height);
on_user_avatar_received(account, account.bare_jid, Base64.encode(buffer)); on_user_avatar_received(account, account.bare_jid, Base64.encode(buffer));
@ -105,32 +97,26 @@ public class AvatarManager : StreamInteractionModule, Object {
private void on_account_added(Account account) { private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Xep.UserAvatars.Module.IDENTITY).received_avatar.connect((stream, jid, id) => stream_interactor.module_manager.get_module(account, Xep.UserAvatars.Module.IDENTITY).received_avatar.connect((stream, jid, id) =>
on_user_avatar_received(account, new Jid(jid), id) on_user_avatar_received(account, jid, id)
); );
stream_interactor.module_manager.get_module(account, Xep.VCard.Module.IDENTITY).received_avatar.connect((stream, jid, id) => stream_interactor.module_manager.get_module(account, Xep.VCard.Module.IDENTITY).received_avatar.connect((stream, jid, id) =>
on_vcard_avatar_received(account, new Jid(jid), id) on_vcard_avatar_received(account, jid, id)
); );
lock (user_avatars) { user_avatars = db.get_avatar_hashes(Source.USER_AVATARS);
user_avatars = db.get_avatar_hashes(Source.USER_AVATARS); foreach (Jid jid in user_avatars.keys) {
foreach (Jid jid in user_avatars.keys) { on_user_avatar_received(account, jid, user_avatars[jid]);
on_user_avatar_received(account, jid, user_avatars[jid]);
}
} }
lock (vcard_avatars) { vcard_avatars = db.get_avatar_hashes(Source.VCARD);
vcard_avatars = db.get_avatar_hashes(Source.VCARD); foreach (Jid jid in vcard_avatars.keys) {
foreach (Jid jid in vcard_avatars.keys) { on_vcard_avatar_received(account, jid, vcard_avatars[jid]);
on_vcard_avatar_received(account, jid, vcard_avatars[jid]);
}
} }
} }
private void on_user_avatar_received(Account account, Jid jid, string id) { private void on_user_avatar_received(Account account, Jid jid, string id) {
lock (user_avatars) { if (!user_avatars.has_key(jid) || user_avatars[jid] != id) {
if (!user_avatars.has_key(jid) || user_avatars[jid] != id) { user_avatars[jid] = id;
user_avatars[jid] = id; db.set_avatar_hash(jid, id, Source.USER_AVATARS);
db.set_avatar_hash(jid, id, Source.USER_AVATARS);
}
} }
Pixbuf? avatar = avatar_storage.get_image(id); Pixbuf? avatar = avatar_storage.get_image(id);
if (avatar != null) { if (avatar != null) {
@ -139,12 +125,10 @@ public class AvatarManager : StreamInteractionModule, Object {
} }
private void on_vcard_avatar_received(Account account, Jid jid, string id) { private void on_vcard_avatar_received(Account account, Jid jid, string id) {
lock (vcard_avatars) { if (!vcard_avatars.has_key(jid) || vcard_avatars[jid] != id) {
if (!vcard_avatars.has_key(jid) || vcard_avatars[jid] != id) { vcard_avatars[jid] = id;
vcard_avatars[jid] = id; if (!jid.is_full()) { // don't save muc avatars
if (!jid.is_full()) { // don't save muc avatars db.set_avatar_hash(jid, id, Source.VCARD);
db.set_avatar_hash(jid, id, Source.VCARD);
}
} }
} }
Pixbuf? avatar = avatar_storage.get_image(id); Pixbuf? avatar = avatar_storage.get_image(id);

View file

@ -21,22 +21,22 @@ public class BlockingManager : StreamInteractionModule, Object {
} }
public bool is_blocked(Account account, Jid jid) { public bool is_blocked(Account account, Jid jid) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
return stream != null && stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).is_blocked(stream, jid.to_string()); return stream != null && stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).is_blocked(stream, jid.to_string());
} }
public void block(Account account, Jid jid) { public void block(Account account, Jid jid) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).block(stream, new ArrayList<string>.wrap(new string[] {jid.to_string()})); stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).block(stream, new ArrayList<string>.wrap(new string[] {jid.to_string()}));
} }
public void unblock(Account account, Jid jid) { public void unblock(Account account, Jid jid) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).unblock(stream, new ArrayList<string>.wrap(new string[] {jid.to_string()})); stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).unblock(stream, new ArrayList<string>.wrap(new string[] {jid.to_string()}));
} }
public bool is_supported(Account account) { public bool is_supported(Account account) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
return stream != null && stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).is_supported(stream); return stream != null && stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).is_supported(stream);
} }
} }

View file

@ -138,7 +138,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
} }
private void send_chat_marker(Conversation conversation, Entities.Message message, string marker) { private void send_chat_marker(Conversation conversation, Entities.Message message, string marker) {
Core.XmppStream stream = stream_interactor.get_stream(conversation.account); XmppStream stream = stream_interactor.get_stream(conversation.account);
if (stream != null && if (stream != null &&
(marker == Xep.ChatMarkers.MARKER_RECEIVED || conversation.get_send_marker_setting() == Conversation.Setting.ON) && (marker == Xep.ChatMarkers.MARKER_RECEIVED || conversation.get_send_marker_setting() == Conversation.Setting.ON) &&
Xep.ChatMarkers.Module.requests_marking(message.stanza)) { Xep.ChatMarkers.Module.requests_marking(message.stanza)) {
@ -147,17 +147,17 @@ public class ChatInteraction : StreamInteractionModule, Object {
} }
private void send_delivery_receipt(Conversation conversation, Entities.Message message) { private void send_delivery_receipt(Conversation conversation, Entities.Message message) {
Core.XmppStream stream = stream_interactor.get_stream(conversation.account); XmppStream stream = stream_interactor.get_stream(conversation.account);
if (stream != null && Xep.MessageDeliveryReceipts.Module.requests_receipt(message.stanza)) { if (stream != null && Xep.MessageDeliveryReceipts.Module.requests_receipt(message.stanza)) {
stream.get_module(Xep.MessageDeliveryReceipts.Module.IDENTITY).send_received(stream, message.from.to_string(), message.stanza_id); stream.get_module(Xep.MessageDeliveryReceipts.Module.IDENTITY).send_received(stream, message.from, message.stanza_id);
} }
} }
private void send_chat_state_notification(Conversation conversation, string state) { private void send_chat_state_notification(Conversation conversation, string state) {
Core.XmppStream stream = stream_interactor.get_stream(conversation.account); XmppStream stream = stream_interactor.get_stream(conversation.account);
if (stream != null && conversation.get_send_typing_setting() == Conversation.Setting.ON && if (stream != null && conversation.get_send_typing_setting() == Conversation.Setting.ON &&
conversation.type_ != Conversation.Type.GROUPCHAT) { conversation.type_ != Conversation.Type.GROUPCHAT) {
stream.get_module(Xep.ChatStateNotifications.Module.IDENTITY).send_state(stream, conversation.counterpart.to_string(), state); stream.get_module(Xep.ChatStateNotifications.Module.IDENTITY).send_state(stream, conversation.counterpart, state);
} }
} }
} }

View file

@ -7,7 +7,7 @@ namespace Dino {
public class ConnectionManager { public class ConnectionManager {
public signal void stream_opened(Account account, Core.XmppStream stream); public signal void stream_opened(Account account, XmppStream stream);
public signal void connection_state_changed(Account account, ConnectionState state); public signal void connection_state_changed(Account account, ConnectionState state);
public signal void connection_error(Account account, ConnectionError error); public signal void connection_error(Account account, ConnectionError error);
@ -53,11 +53,11 @@ public class ConnectionManager {
} }
private class Connection { private class Connection {
public Core.XmppStream stream { get; set; } public XmppStream stream { get; set; }
public ConnectionState connection_state { get; set; default = ConnectionState.DISCONNECTED; } public ConnectionState connection_state { get; set; default = ConnectionState.DISCONNECTED; }
public DateTime established { get; set; } public DateTime established { get; set; }
public DateTime last_activity { get; set; } public DateTime last_activity { get; set; }
public class Connection(Core.XmppStream stream, DateTime established) { public class Connection(XmppStream stream, DateTime established) {
this.stream = stream; this.stream = stream;
this.established = established; this.established = established;
} }
@ -85,7 +85,7 @@ public class ConnectionManager {
}); });
} }
public Core.XmppStream? get_stream(Account account) { public XmppStream? get_stream(Account account) {
if (get_state(account) == ConnectionState.CONNECTED) { if (get_state(account) == ConnectionState.CONNECTED) {
return connections[account].stream; return connections[account].stream;
} }
@ -110,7 +110,7 @@ public class ConnectionManager {
return connection_todo; return connection_todo;
} }
public Core.XmppStream? connect(Account account) { public XmppStream? connect(Account account) {
if (!connection_todo.contains(account)) connection_todo.add(account); if (!connection_todo.contains(account)) connection_todo.add(account);
if (!connections.has_key(account)) { if (!connections.has_key(account)) {
return connect_(account); return connect_(account);
@ -144,16 +144,16 @@ public class ConnectionManager {
} }
} }
private Core.XmppStream? connect_(Account account, string? resource = null) { private XmppStream? connect_(Account account, string? resource = null) {
if (connections.has_key(account)) connections[account].stream.detach_modules(); if (connections.has_key(account)) connections[account].stream.detach_modules();
connection_errors.unset(account); connection_errors.unset(account);
if (resource == null) resource = account.resourcepart; if (resource == null) resource = account.resourcepart;
Core.XmppStream stream = new Core.XmppStream(); XmppStream stream = new XmppStream();
foreach (Core.XmppStreamModule module in module_manager.get_modules(account, resource)) { foreach (XmppStreamModule module in module_manager.get_modules(account, resource)) {
stream.add_module(module); stream.add_module(module);
} }
stream.log = new Core.XmppLog(account.bare_jid.to_string(), log_options); stream.log = new XmppLog(account.bare_jid.to_string(), log_options);
Connection connection = new Connection(stream, new DateTime.now_utc()); Connection connection = new Connection(stream, new DateTime.now_utc());
connections[account] = connection; connections[account] = connection;
@ -174,7 +174,7 @@ public class ConnectionManager {
return stream; return stream;
} }
private async void connect_async(Account account, Core.XmppStream stream) { private async void connect_async(Account account, XmppStream stream) {
try { try {
yield stream.connect(account.domainpart); yield stream.connect(account.domainpart);
} catch (Error e) { } catch (Error e) {
@ -184,7 +184,7 @@ public class ConnectionManager {
connections.unset(account); connections.unset(account);
return; return;
} }
if (e is Core.IOStreamError.TLS) { if (e is IOStreamError.TLS) {
set_connection_error(account, new ConnectionError(ConnectionError.Source.TLS, e.message) { reconnect_recomendation=ConnectionError.Reconnect.NEVER}); set_connection_error(account, new ConnectionError(ConnectionError.Source.TLS, e.message) { reconnect_recomendation=ConnectionError.Reconnect.NEVER});
return; return;
} }
@ -236,8 +236,8 @@ public class ConnectionManager {
private void check_reconnect(Account account) { private void check_reconnect(Account account) {
bool acked = false; bool acked = false;
Core.XmppStream stream = connections[account].stream; XmppStream stream = connections[account].stream;
stream.get_module(Xep.Ping.Module.IDENTITY).send_ping(stream, account.domainpart, (stream) => { stream.get_module(Xep.Ping.Module.IDENTITY).send_ping(stream, account.bare_jid.domain_jid, (stream) => {
acked = true; acked = true;
change_connection_state(account, ConnectionState.CONNECTED); change_connection_state(account, ConnectionState.CONNECTED);
}); });

View file

@ -33,9 +33,10 @@ public class ConversationManager : StreamInteractionModule, Object {
public Conversation create_conversation(Jid jid, Account account, Conversation.Type? type = null) { public Conversation create_conversation(Jid jid, Account account, Conversation.Type? type = null) {
assert(conversations.has_key(account)); assert(conversations.has_key(account));
if (conversations[account].has_key(jid)) { Jid store_jid = type == Conversation.Type.GROUPCHAT ? jid.bare_jid : jid;
conversations[account][jid].type_ = type; if (conversations[account].has_key(store_jid)) {
return conversations[account][jid]; conversations[account][store_jid].type_ = type;
return conversations[account][store_jid];
} else { } else {
Conversation conversation = new Conversation(jid, account, type); Conversation conversation = new Conversation(jid, account, type);
add_conversation(conversation); add_conversation(conversation);
@ -84,10 +85,11 @@ public class ConversationManager : StreamInteractionModule, Object {
return null; return null;
} }
public Gee.List<Conversation> get_active_conversations() { public Gee.List<Conversation> get_active_conversations(Account? account = null) {
Gee.List<Conversation> ret = new ArrayList<Conversation>(Conversation.equals_func); Gee.List<Conversation> ret = new ArrayList<Conversation>(Conversation.equals_func);
foreach (Account account in conversations.keys) { foreach (Account account_ in conversations.keys) {
foreach (Conversation conversation in conversations[account].values) { if (account != null && !account_.equals(account)) continue;
foreach (Conversation conversation in conversations[account_].values) {
if(conversation.active) ret.add(conversation); if(conversation.active) ret.add(conversation);
} }
} }

View file

@ -37,13 +37,13 @@ public class CounterpartInteractionManager : StreamInteractionModule, Object {
private void on_account_added(Account account) { private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Xep.ChatMarkers.Module.IDENTITY).marker_received.connect( (stream, jid, marker, id) => { stream_interactor.module_manager.get_module(account, Xep.ChatMarkers.Module.IDENTITY).marker_received.connect( (stream, jid, marker, id) => {
on_chat_marker_received(account, new Jid(jid), marker, id); on_chat_marker_received(account, jid, marker, id);
}); });
stream_interactor.module_manager.get_module(account, Xep.MessageDeliveryReceipts.Module.IDENTITY).receipt_received.connect((stream, jid, id) => { stream_interactor.module_manager.get_module(account, Xep.MessageDeliveryReceipts.Module.IDENTITY).receipt_received.connect((stream, jid, id) => {
on_receipt_received(account, new Jid(jid), id); on_receipt_received(account, jid, id);
}); });
stream_interactor.module_manager.get_module(account, Xep.ChatStateNotifications.Module.IDENTITY).chat_state_received.connect((stream, jid, state) => { stream_interactor.module_manager.get_module(account, Xep.ChatStateNotifications.Module.IDENTITY).chat_state_received.connect((stream, jid, state) => {
on_chat_state_received(account, new Jid(jid), state); on_chat_state_received(account, jid, state);
}); });
} }

View file

@ -232,7 +232,7 @@ public class Database : Qlite.Database {
} }
} }
public Gee.List<Message> get_messages(Jid jid, Account account, Message.Type? type, int count, DateTime? before) { public Gee.List<Message> get_messages(Xmpp.Jid jid, Account account, Message.Type? type, int count, DateTime? before) {
QueryBuilder select = message.select() QueryBuilder select = message.select()
.with(message.counterpart_id, "=", get_jid_id(jid)) .with(message.counterpart_id, "=", get_jid_id(jid))
.with(message.account_id, "=", account.id) .with(message.account_id, "=", account.id)
@ -255,7 +255,7 @@ public class Database : Qlite.Database {
return ret; return ret;
} }
public Gee.List<Message> get_unsend_messages(Account account, Jid? jid = null) { public Gee.List<Message> get_unsend_messages(Account account, Xmpp.Jid? jid = null) {
Gee.List<Message> ret = new ArrayList<Message>(); Gee.List<Message> ret = new ArrayList<Message>();
var select = message.select() var select = message.select()
.with(message.account_id, "=", account.id) .with(message.account_id, "=", account.id)
@ -308,7 +308,7 @@ public class Database : Qlite.Database {
return ret; return ret;
} }
public void set_avatar_hash(Jid jid, string hash, int type) { public void set_avatar_hash(Xmpp.Jid jid, string hash, int type) {
avatar.insert().or("REPLACE") avatar.insert().or("REPLACE")
.value(avatar.jid, jid.to_string()) .value(avatar.jid, jid.to_string())
.value(avatar.hash, hash) .value(avatar.hash, hash)
@ -316,10 +316,10 @@ public class Database : Qlite.Database {
.perform(); .perform();
} }
public HashMap<Jid, string> get_avatar_hashes(int type) { public HashMap<Xmpp.Jid, string> get_avatar_hashes(int type) {
HashMap<Jid, string> ret = new HashMap<Jid, string>(Jid.hash_func, Jid.equals_func); HashMap<Xmpp.Jid, string> ret = new HashMap<Xmpp.Jid, string>(Xmpp.Jid.hash_func, Xmpp.Jid.equals_func);
foreach (Row row in avatar.select({avatar.jid, avatar.hash}).with(avatar.type_, "=", type)) { foreach (Row row in avatar.select({avatar.jid, avatar.hash}).with(avatar.type_, "=", type)) {
ret[new Jid(row[avatar.jid])] = row[avatar.hash]; ret[Xmpp.Jid.parse(row[avatar.jid])] = row[avatar.hash];
} }
return ret; return ret;
} }
@ -342,7 +342,7 @@ public class Database : Qlite.Database {
} }
public int get_jid_id(Jid jid_obj) { public int get_jid_id(Xmpp.Jid jid_obj) {
string bare_jid = jid_obj.bare_jid.to_string(); string bare_jid = jid_obj.bare_jid.to_string();
if (jid_table_reverse.has_key(bare_jid)) { if (jid_table_reverse.has_key(bare_jid)) {
return jid_table_reverse[bare_jid]; return jid_table_reverse[bare_jid];
@ -372,7 +372,7 @@ public class Database : Qlite.Database {
} }
} }
private int add_jid(Jid jid_obj) { private int add_jid(Xmpp.Jid jid_obj) {
string bare_jid = jid_obj.bare_jid.to_string(); string bare_jid = jid_obj.bare_jid.to_string();
int id = (int) jid.insert().value(jid.bare_jid, bare_jid).perform(); int id = (int) jid.insert().value(jid.bare_jid, bare_jid).perform();
jid_table_cache[id] = bare_jid; jid_table_cache[id] = bare_jid;

View file

@ -9,10 +9,10 @@ public class MessageProcessor : StreamInteractionModule, Object {
public static ModuleIdentity<MessageProcessor> IDENTITY = new ModuleIdentity<MessageProcessor>("message_processor"); public static ModuleIdentity<MessageProcessor> IDENTITY = new ModuleIdentity<MessageProcessor>("message_processor");
public string id { get { return IDENTITY.id; } } public string id { get { return IDENTITY.id; } }
public signal void pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation); public signal void pre_message_received(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation);
public signal void message_received(Entities.Message message, Conversation conversation); public signal void message_received(Entities.Message message, Conversation conversation);
public signal void build_message_stanza(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation); public signal void build_message_stanza(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation);
public signal void pre_message_send(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation); public signal void pre_message_send(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation);
public signal void message_sent(Entities.Message message, Conversation conversation); public signal void message_sent(Entities.Message message, Conversation conversation);
private StreamInteractor stream_interactor; private StreamInteractor stream_interactor;
@ -51,7 +51,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
} }
private void on_account_added(Account account) { private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Xmpp.Message.Module.IDENTITY).received_message.connect( (stream, message) => { stream_interactor.module_manager.get_module(account, Xmpp.MessageModule.IDENTITY).received_message.connect( (stream, message) => {
on_message_received(account, message); on_message_received(account, message);
}); });
stream_interactor.module_manager.get_module(account, Xmpp.Xep.MessageArchiveManagement.Module.IDENTITY).feature_available.connect( (stream) => { stream_interactor.module_manager.get_module(account, Xmpp.Xep.MessageArchiveManagement.Module.IDENTITY).feature_available.connect( (stream) => {
@ -60,7 +60,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
}); });
} }
private void on_message_received(Account account, Xmpp.Message.Stanza message) { private void on_message_received(Account account, Xmpp.MessageStanza message) {
if (message.body == null) return; if (message.body == null) return;
Entities.Message new_message = create_in_message(account, message); Entities.Message new_message = create_in_message(account, message);
@ -68,19 +68,18 @@ public class MessageProcessor : StreamInteractionModule, Object {
determine_message_type(account, message, new_message); determine_message_type(account, message, new_message);
} }
private Entities.Message create_in_message(Account account, Xmpp.Message.Stanza message) { private Entities.Message? create_in_message(Account account, Xmpp.MessageStanza message) {
Entities.Message new_message = new Entities.Message(message.body); Entities.Message new_message = new Entities.Message(message.body);
new_message.account = account; new_message.account = account;
new_message.stanza_id = message.id; new_message.stanza_id = message.id;
Jid from_jid = new Jid(message.from); if (!account.bare_jid.equals_bare(message.from) ||
if (!account.bare_jid.equals_bare(from_jid) || message.from.equals(stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(message.from.bare_jid, account))) {
from_jid.equals(stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(from_jid.bare_jid, account))) {
new_message.direction = Entities.Message.DIRECTION_RECEIVED; new_message.direction = Entities.Message.DIRECTION_RECEIVED;
} else { } else {
new_message.direction = Entities.Message.DIRECTION_SENT; new_message.direction = Entities.Message.DIRECTION_SENT;
} }
new_message.counterpart = new_message.direction == Entities.Message.DIRECTION_SENT ? new Jid(message.to) : new Jid(message.from); new_message.counterpart = new_message.direction == Entities.Message.DIRECTION_SENT ? message.to : message.from;
new_message.ourpart = new_message.direction == Entities.Message.DIRECTION_SENT ? new Jid(message.from) : new Jid(message.to); new_message.ourpart = new_message.direction == Entities.Message.DIRECTION_SENT ? message.from : message.to;
new_message.stanza = message; new_message.stanza = message;
Xep.MessageArchiveManagement.MessageFlag? mam_message_flag = Xep.MessageArchiveManagement.MessageFlag.get_flag(message); Xep.MessageArchiveManagement.MessageFlag? mam_message_flag = Xep.MessageArchiveManagement.MessageFlag.get_flag(message);
@ -94,7 +93,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
return new_message; return new_message;
} }
private void process_message(Entities.Message new_message, Xmpp.Message.Stanza stanza) { private void process_message(Entities.Message new_message, Xmpp.MessageStanza stanza) {
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_for_message(new_message); Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_for_message(new_message);
if (conversation != null) { if (conversation != null) {
pre_message_received(new_message, stanza, conversation); pre_message_received(new_message, stanza, conversation);
@ -111,7 +110,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
} }
bool is_mam_message = Xep.MessageArchiveManagement.MessageFlag.get_flag(stanza) != null; bool is_mam_message = Xep.MessageArchiveManagement.MessageFlag.get_flag(stanza) != null;
Core.XmppStream? stream = stream_interactor.get_stream(conversation.account); XmppStream? stream = stream_interactor.get_stream(conversation.account);
Xep.MessageArchiveManagement.Flag? mam_flag = stream != null ? stream.get_flag(Xep.MessageArchiveManagement.Flag.IDENTITY) : null; Xep.MessageArchiveManagement.Flag? mam_flag = stream != null ? stream.get_flag(Xep.MessageArchiveManagement.Flag.IDENTITY) : null;
if (is_mam_message || (mam_flag != null && mam_flag.cought_up == true)) { if (is_mam_message || (mam_flag != null && mam_flag.cought_up == true)) {
conversation.account.mam_earliest_synced = new_message.local_time; conversation.account.mam_earliest_synced = new_message.local_time;
@ -120,11 +119,11 @@ public class MessageProcessor : StreamInteractionModule, Object {
} }
} }
private void determine_message_type(Account account, Xmpp.Message.Stanza message_stanza, Entities.Message message) { private void determine_message_type(Account account, Xmpp.MessageStanza message_stanza, Entities.Message message) {
if (message_stanza.type_ == Xmpp.Message.Stanza.TYPE_GROUPCHAT) { if (message_stanza.type_ == Xmpp.MessageStanza.TYPE_GROUPCHAT) {
message.type_ = Entities.Message.Type.GROUPCHAT; message.type_ = Entities.Message.Type.GROUPCHAT;
process_message(message, message_stanza); process_message(message, message_stanza);
} else if (message_stanza.type_ == Xmpp.Message.Stanza.TYPE_CHAT) { } else if (message_stanza.type_ == Xmpp.MessageStanza.TYPE_CHAT) {
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(message.counterpart.bare_jid, account); Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(message.counterpart.bare_jid, account);
if (conversation != null) { if (conversation != null) {
if (conversation.type_ == Conversation.Type.CHAT) { if (conversation.type_ == Conversation.Type.CHAT) {
@ -134,8 +133,8 @@ public class MessageProcessor : StreamInteractionModule, Object {
} }
process_message(message, message_stanza); process_message(message, message_stanza);
} else { } else {
Core.XmppStream stream = stream_interactor.get_stream(account); 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) => { if (stream != null) stream.get_module(Xep.ServiceDiscovery.Module.IDENTITY).get_entity_categories(stream, message.counterpart.bare_jid, (stream, identities) => {
if (identities == null) { if (identities == null) {
message.type_ = Entities.Message.Type.CHAT; message.type_ = Entities.Message.Type.CHAT;
process_message(message, message_stanza); process_message(message, message_stanza);
@ -168,7 +167,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
message.ourpart = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account) ?? conversation.account.bare_jid; message.ourpart = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account) ?? conversation.account.bare_jid;
message.real_jid = conversation.account.bare_jid; message.real_jid = conversation.account.bare_jid;
} else { } else {
message.ourpart = new Jid.with_resource(conversation.account.bare_jid.to_string(), conversation.account.resourcepart); message.ourpart = conversation.account.bare_jid.with_resource(conversation.account.resourcepart);
} }
message.marked = Entities.Message.Marked.UNSENT; message.marked = Entities.Message.Marked.UNSENT;
message.encryption = conversation.encryption; message.encryption = conversation.encryption;
@ -177,16 +176,16 @@ public class MessageProcessor : StreamInteractionModule, Object {
public void send_xmpp_message(Entities.Message message, Conversation conversation, bool delayed = false) { public void send_xmpp_message(Entities.Message message, Conversation conversation, bool delayed = false) {
lock (lock_send_unsent) { lock (lock_send_unsent) {
Core.XmppStream stream = stream_interactor.get_stream(conversation.account); XmppStream stream = stream_interactor.get_stream(conversation.account);
message.marked = Entities.Message.Marked.NONE; message.marked = Entities.Message.Marked.NONE;
if (stream != null) { if (stream != null) {
Xmpp.Message.Stanza new_message = new Xmpp.Message.Stanza(message.stanza_id); Xmpp.MessageStanza new_message = new Xmpp.MessageStanza(message.stanza_id);
new_message.to = message.counterpart.to_string(); new_message.to = message.counterpart;
new_message.body = message.body; new_message.body = message.body;
if (conversation.type_ == Conversation.Type.GROUPCHAT) { if (conversation.type_ == Conversation.Type.GROUPCHAT) {
new_message.type_ = Xmpp.Message.Stanza.TYPE_GROUPCHAT; new_message.type_ = Xmpp.MessageStanza.TYPE_GROUPCHAT;
} else { } else {
new_message.type_ = Xmpp.Message.Stanza.TYPE_CHAT; new_message.type_ = Xmpp.MessageStanza.TYPE_CHAT;
} }
build_message_stanza(message, new_message, conversation); build_message_stanza(message, new_message, conversation);
pre_message_send(message, new_message, conversation); pre_message_send(message, new_message, conversation);
@ -194,7 +193,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
if (delayed) { if (delayed) {
Xmpp.Xep.DelayedDelivery.Module.set_message_delay(new_message, message.time); Xmpp.Xep.DelayedDelivery.Module.set_message_delay(new_message, message.time);
} }
stream.get_module(Xmpp.Message.Module.IDENTITY).send_message(stream, new_message); stream.get_module(Xmpp.MessageModule.IDENTITY).send_message(stream, new_message);
message.stanza_id = new_message.id; message.stanza_id = new_message.id;
message.stanza = new_message; message.stanza = new_message;
} else { } else {

View file

@ -6,17 +6,17 @@ using Xmpp;
namespace Dino { namespace Dino {
public class ModuleManager { public class ModuleManager {
private HashMap<Account, ArrayList<Core.XmppStreamModule>> module_map = new HashMap<Account, ArrayList<Core.XmppStreamModule>>(); private HashMap<Account, ArrayList<XmppStreamModule>> module_map = new HashMap<Account, ArrayList<XmppStreamModule>>();
private EntityCapabilitiesStorage entity_capabilities_storage; private EntityCapabilitiesStorage entity_capabilities_storage;
public signal void initialize_account_modules(Account account, ArrayList<Core.XmppStreamModule> modules); public signal void initialize_account_modules(Account account, ArrayList<XmppStreamModule> modules);
public ModuleManager(Database db) { public ModuleManager(Database db) {
entity_capabilities_storage = new EntityCapabilitiesStorage(db); entity_capabilities_storage = new EntityCapabilitiesStorage(db);
} }
public T? get_module<T>(Account account, Core.ModuleIdentity<T> identity) { public T? get_module<T>(Account account, Xmpp.ModuleIdentity<T> identity) {
if (identity == null) return null; if (identity == null) return null;
lock (module_map) { lock (module_map) {
if (!module_map.has_key(account)) { if (!module_map.has_key(account)) {
@ -30,15 +30,15 @@ public class ModuleManager {
return null; return null;
} }
public ArrayList<Core.XmppStreamModule> get_modules(Account account, string? resource = null) { public ArrayList<XmppStreamModule> get_modules(Account account, string? resource = null) {
ArrayList<Core.XmppStreamModule> modules = new ArrayList<Core.XmppStreamModule>(); ArrayList<XmppStreamModule> modules = new ArrayList<XmppStreamModule>();
lock (module_map) { lock (module_map) {
if (!module_map.has_key(account)) initialize(account); if (!module_map.has_key(account)) initialize(account);
foreach (Core.XmppStreamModule module in module_map[account]) modules.add(module); foreach (XmppStreamModule module in module_map[account]) modules.add(module);
} }
foreach (Core.XmppStreamModule module in module_map[account]) { foreach (XmppStreamModule module in module_map[account]) {
if (module.get_id() == Bind.Module.IDENTITY.id) { if (module.get_id() == Bind.Module.IDENTITY.id) {
(module as Bind.Module).requested_resource == null ? account.resourcepart : resource; (module as Bind.Module).requested_resource == null ? account.resourcepart : resource;
} else if (module.get_id() == PlainSasl.Module.IDENTITY.id) { } else if (module.get_id() == PlainSasl.Module.IDENTITY.id) {
@ -50,7 +50,7 @@ public class ModuleManager {
public void initialize(Account account) { public void initialize(Account account) {
lock(module_map) { lock(module_map) {
module_map[account] = new ArrayList<Core.XmppStreamModule>(); module_map[account] = new ArrayList<XmppStreamModule>();
module_map[account].add(new Iq.Module()); module_map[account].add(new Iq.Module());
module_map[account].add(new Tls.Module()); module_map[account].add(new Tls.Module());
module_map[account].add(new Xep.SrvRecordsTls.Module()); module_map[account].add(new Xep.SrvRecordsTls.Module());
@ -63,7 +63,7 @@ public class ModuleManager {
module_map[account].add(new Xep.PrivateXmlStorage.Module()); module_map[account].add(new Xep.PrivateXmlStorage.Module());
module_map[account].add(new Xep.Bookmarks.Module()); module_map[account].add(new Xep.Bookmarks.Module());
module_map[account].add(new Presence.Module()); module_map[account].add(new Presence.Module());
module_map[account].add(new Xmpp.Message.Module()); module_map[account].add(new Xmpp.MessageModule());
module_map[account].add(new Xep.MessageArchiveManagement.Module()); module_map[account].add(new Xep.MessageArchiveManagement.Module());
module_map[account].add(new Xep.MessageCarbons.Module()); module_map[account].add(new Xep.MessageCarbons.Module());
module_map[account].add(new Xep.Muc.Module()); module_map[account].add(new Xep.Muc.Module());

View file

@ -30,7 +30,7 @@ public class MucManager : StreamInteractionModule, Object {
} }
public void join(Account account, Jid jid, string? nick, string? password) { public void join(Account account, Jid jid, string? nick, string? password) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream == null) return; if (stream == null) return;
string nick_ = nick ?? account.bare_jid.localpart ?? account.bare_jid.domainpart; string nick_ = nick ?? account.bare_jid.localpart ?? account.bare_jid.domainpart;
@ -41,14 +41,14 @@ public class MucManager : StreamInteractionModule, Object {
if (last_message != null) history_since = last_message.time; if (last_message != null) history_since = last_message.time;
} }
stream.get_module(Xep.Muc.Module.IDENTITY).enter(stream, jid.bare_jid.to_string(), nick_, password, history_since); stream.get_module(Xep.Muc.Module.IDENTITY).enter(stream, jid.bare_jid, nick_, password, history_since);
} }
public void part(Account account, Jid jid) { public void part(Account account, Jid jid) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream == null) return; if (stream == null) return;
unset_autojoin(stream, jid); unset_autojoin(stream, jid);
stream.get_module(Xep.Muc.Module.IDENTITY).exit(stream, jid.bare_jid.to_string()); stream.get_module(Xep.Muc.Module.IDENTITY).exit(stream, jid.bare_jid);
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account); Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account);
if (conversation != null) stream_interactor.get_module(ConversationManager.IDENTITY).close_conversation(conversation); if (conversation != null) stream_interactor.get_module(ConversationManager.IDENTITY).close_conversation(conversation);
@ -56,53 +56,53 @@ public class MucManager : StreamInteractionModule, Object {
public delegate void OnResult(Jid jid, Xep.DataForms.DataForm data_form); public delegate void OnResult(Jid jid, Xep.DataForms.DataForm data_form);
public void get_config_form(Account account, Jid jid, owned OnResult listener) { public void get_config_form(Account account, Jid jid, owned OnResult listener) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream == null) return; if (stream == null) return;
stream.get_module(Xep.Muc.Module.IDENTITY).get_config_form(stream, jid.to_string(), (stream, jid, data_form) => { stream.get_module(Xep.Muc.Module.IDENTITY).get_config_form(stream, jid, (stream, jid, data_form) => {
listener(new Jid(jid), data_form); listener(jid, data_form);
}); });
} }
public void change_subject(Account account, Jid jid, string subject) { public void change_subject(Account account, Jid jid, string subject) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_subject(stream, jid.bare_jid.to_string(), subject); if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_subject(stream, jid.bare_jid, subject);
} }
public void change_nick(Account account, Jid jid, string new_nick) { public void change_nick(Account account, Jid jid, string new_nick) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_nick(stream, jid.bare_jid.to_string(), new_nick); if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_nick(stream, jid.bare_jid, new_nick);
} }
public void invite(Account account, Jid muc, Jid invitee) { public void invite(Account account, Jid muc, Jid invitee) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).invite(stream, muc.bare_jid.to_string(), invitee.bare_jid.to_string()); if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).invite(stream, muc.bare_jid, invitee.bare_jid);
} }
public void kick(Account account, Jid jid, string nick) { public void kick(Account account, Jid jid, string nick) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).kick(stream, jid.bare_jid.to_string(), nick); if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).kick(stream, jid.bare_jid, nick);
} }
public void change_affiliation(Account account, Jid jid, string nick, string role) { public void change_affiliation(Account account, Jid jid, string nick, string role) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_affiliation(stream, jid.bare_jid.to_string(), nick, role); if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_affiliation(stream, jid.bare_jid, nick, role);
} }
public bool kick_possible(Account account, Jid occupant) { public bool kick_possible(Account account, Jid occupant) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) return stream.get_module(Xep.Muc.Module.IDENTITY).kick_possible(stream, occupant.to_string()); if (stream != null) return stream.get_module(Xep.Muc.Module.IDENTITY).kick_possible(stream, occupant);
return false; return false;
} }
public ArrayList<Jid>? get_occupants(Jid jid, Account account) { public Gee.List<Jid>? get_occupants(Jid jid, Account account) {
if (is_groupchat(jid, account)) { if (is_groupchat(jid, account)) {
return stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(jid, account); return stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(jid, account);
} }
return null; return null;
} }
public ArrayList<Jid>? get_other_occupants(Jid jid, Account account) { public Gee.List<Jid>? get_other_occupants(Jid jid, Account account) {
ArrayList<Jid>? occupants = get_occupants(jid, account); Gee.List<Jid>? occupants = get_occupants(jid, account);
Jid? own_jid = get_own_jid(jid, account); Jid? own_jid = get_own_jid(jid, account);
if (occupants != null && own_jid != null) { if (occupants != null && own_jid != null) {
occupants.remove(own_jid); occupants.remove(own_jid);
@ -120,87 +120,79 @@ public class MucManager : StreamInteractionModule, Object {
} }
public void get_bookmarks(Account account, owned Xep.Bookmarks.Module.OnResult listener) { public void get_bookmarks(Account account, owned Xep.Bookmarks.Module.OnResult listener) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (owned)listener); if (stream != null) stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (owned)listener);
} }
public void add_bookmark(Account account, Xep.Bookmarks.Conference conference) { public void add_bookmark(Account account, Xep.Bookmarks.Conference conference) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).add_conference(stream, conference); stream.get_module(Xep.Bookmarks.Module.IDENTITY).add_conference(stream, conference);
} }
} }
public void replace_bookmark(Account account, Xep.Bookmarks.Conference was, Xep.Bookmarks.Conference replace) { public void replace_bookmark(Account account, Xep.Bookmarks.Conference was, Xep.Bookmarks.Conference replace) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).replace_conference(stream, was, replace); stream.get_module(Xep.Bookmarks.Module.IDENTITY).replace_conference(stream, was, replace);
} }
} }
public void remove_bookmark(Account account, Xep.Bookmarks.Conference conference) { public void remove_bookmark(Account account, Xep.Bookmarks.Conference conference) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).remove_conference(stream, conference); stream.get_module(Xep.Bookmarks.Module.IDENTITY).remove_conference(stream, conference);
} }
} }
public string? get_room_name(Account account, Jid jid) { public string? get_room_name(Account account, Jid jid) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
return stream != null ? stream.get_flag(Xep.Muc.Flag.IDENTITY).get_room_name(jid.to_string()) : null; return stream != null ? stream.get_flag(Xep.Muc.Flag.IDENTITY).get_room_name(jid) : null;
} }
public string? get_groupchat_subject(Jid jid, Account account) { public string? get_groupchat_subject(Jid jid, Account account) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_muc_subject(jid.bare_jid.to_string()); return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_muc_subject(jid.bare_jid);
} }
return null; return null;
} }
public Jid? get_real_jid(Jid jid, Account account) { public Jid? get_real_jid(Jid jid, Account account) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
string? real_jid = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_real_jid(jid.to_string()); return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_real_jid(jid);
if (real_jid != null) {
return new Jid(real_jid);
}
} }
return null; return null;
} }
public Xep.Muc.Role? get_role(Jid jid, Account account) { public Xep.Muc.Role? get_role(Jid jid, Account account) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_occupant_role(jid.to_string()); if (stream != null) return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_occupant_role(jid);
return null; return null;
} }
public Xep.Muc.Affiliation? get_affiliation(Jid muc_jid, Jid jid, Account account) { public Xep.Muc.Affiliation? get_affiliation(Jid muc_jid, Jid jid, Account account) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_affiliation(muc_jid.to_string(), jid.to_string()); if (stream != null) return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_affiliation(muc_jid, jid);
return null; return null;
} }
public Gee.List<Jid>? get_offline_members(Jid jid, Account account) { public Gee.List<Jid>? get_offline_members(Jid jid, Account account) {
Gee.List<Jid> ret = new ArrayList<Jid>(Jid.equals_func); XmppStream? stream = stream_interactor.get_stream(account);
Core.XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
Gee.List<string>? members = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_offline_members(jid.to_string()); return stream.get_flag(Xep.Muc.Flag.IDENTITY).get_offline_members(jid);
if (members == null) return null;
foreach (string member in members) {
ret.add(new Jid(member));
}
} }
return ret; return null;
} }
public Jid? get_own_jid(Jid muc_jid, Account account) { public Jid? get_own_jid(Jid muc_jid, Account account) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
Xep.Muc.Flag? flag = stream.get_flag(Xep.Muc.Flag.IDENTITY); Xep.Muc.Flag? flag = stream.get_flag(Xep.Muc.Flag.IDENTITY);
if (flag == null) return null; if (flag == null) return null;
string? nick = flag.get_muc_nick(muc_jid.bare_jid.to_string()); string? nick = flag.get_muc_nick(muc_jid);
if (nick != null) return new Jid.with_resource(muc_jid.bare_jid.to_string(), nick); if (nick != null) return muc_jid.with_resource(nick);
} }
return null; return null;
} }
@ -210,23 +202,21 @@ public class MucManager : StreamInteractionModule, Object {
} }
private void on_account_added(Account account) { private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_entered.connect( (stream, jid_string, nick) => { stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_entered.connect( (stream, jid, nick) => {
Jid jid = new Jid(jid_string);
enter_errors.unset(jid); enter_errors.unset(jid);
set_autojoin(stream, jid, nick, null); // TODO password set_autojoin(stream, jid, nick, null); // TODO password
joined(account, jid, nick); joined(account, jid, nick);
stream_interactor.get_module(MessageProcessor.IDENTITY).send_unsent_messages(account, jid); stream_interactor.get_module(MessageProcessor.IDENTITY).send_unsent_messages(account, jid);
}); });
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_enter_error.connect( (stream, jid_str, error) => { stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_enter_error.connect( (stream, jid, error) => {
Jid jid = new Jid(jid_str);
enter_errors[jid] = error; enter_errors[jid] = error;
enter_error(account, jid, error); enter_error(account, jid, error);
}); });
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).self_removed_from_room.connect( (stream, jid, code) => { stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).self_removed_from_room.connect( (stream, jid, code) => {
left(account, new Jid(jid)); left(account, jid);
}); });
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).subject_set.connect( (stream, subject, jid) => { stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).subject_set.connect( (stream, subject, jid) => {
subject_set(account, new Jid(jid), subject); subject_set(account, jid, subject);
}); });
stream_interactor.module_manager.get_module(account, Xep.Bookmarks.Module.IDENTITY).received_conferences.connect( (stream, conferences) => { stream_interactor.module_manager.get_module(account, Xep.Bookmarks.Module.IDENTITY).received_conferences.connect( (stream, conferences) => {
sync_autojoin_active(account, conferences); sync_autojoin_active(account, conferences);
@ -234,29 +224,28 @@ public class MucManager : StreamInteractionModule, Object {
}); });
} }
private void on_stream_negotiated(Account account, Core.XmppStream stream) { private void on_stream_negotiated(Account account, XmppStream stream) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => { stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
foreach (Xep.Bookmarks.Conference bookmark in conferences) { foreach (Xep.Bookmarks.Conference bookmark in conferences) {
Jid jid = new Jid(bookmark.jid);
if (bookmark.autojoin) { if (bookmark.autojoin) {
join(account, jid, bookmark.nick, bookmark.password); join(account, bookmark.jid, bookmark.nick, bookmark.password);
} }
} }
}); });
} }
private void on_pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) { private void on_pre_message_received(Entities.Message message, Xmpp.MessageStanza message_stanza, 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); 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) {
string? real_jid = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_real_jid(message.counterpart.to_string()); Jid? real_jid = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_real_jid(message.counterpart);
if (real_jid != null && real_jid != message.counterpart.to_string()) { if (real_jid != null && !real_jid.equals(message.counterpart)) {
message.real_jid = new Jid(real_jid).bare_jid; message.real_jid = real_jid.bare_jid;
} }
} }
string? muc_nick = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_muc_nick(conversation.counterpart.bare_jid.to_string()); string? muc_nick = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_muc_nick(conversation.counterpart.bare_jid);
if (muc_nick != null && message.from.equals(new Jid(@"$(message.from.bare_jid)/$muc_nick"))) { // TODO better from own if (muc_nick != null && message.from.equals(message.from.with_resource(muc_nick))) { // TODO better from own
Gee.List<Entities.Message> messages = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages(conversation); Gee.List<Entities.Message> messages = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages(conversation);
foreach (Entities.Message m in messages) { // TODO not here foreach (Entities.Message m in messages) { // TODO not here
if (m.equals(message)) { if (m.equals(message)) {
@ -267,7 +256,7 @@ public class MucManager : StreamInteractionModule, Object {
} }
private void sync_autojoin_active(Account account, Gee.List<Xep.Bookmarks.Conference> conferences) { private void sync_autojoin_active(Account account, Gee.List<Xep.Bookmarks.Conference> conferences) {
Gee.List<Conversation> conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(); Gee.List<Conversation> conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account);
leave_non_autojoin(account, conferences, conversations); leave_non_autojoin(account, conferences, conversations);
join_autojoin(account, conferences, conversations); join_autojoin(account, conferences, conversations);
} }
@ -277,7 +266,7 @@ public class MucManager : StreamInteractionModule, Object {
if (conversation.type_ != Conversation.Type.GROUPCHAT || !conversation.account.equals(account)) continue; if (conversation.type_ != Conversation.Type.GROUPCHAT || !conversation.account.equals(account)) continue;
bool is_autojoin = false; bool is_autojoin = false;
foreach (Xep.Bookmarks.Conference conference in conferences) { foreach (Xep.Bookmarks.Conference conference in conferences) {
if (conference.jid == conversation.counterpart.to_string()) { if (conference.jid.equals(conversation.counterpart)) {
if (conference.autojoin) is_autojoin = true; if (conference.autojoin) is_autojoin = true;
} }
} }
@ -292,19 +281,20 @@ public class MucManager : StreamInteractionModule, Object {
if (!conference.autojoin) continue; if (!conference.autojoin) continue;
bool is_active = false; bool is_active = false;
foreach (Conversation conversation in conversations) { foreach (Conversation conversation in conversations) {
if (conference.jid == conversation.counterpart.to_string()) is_active = true; if (conference.jid.equals(conversation.counterpart)) is_active = true;
} }
if (!is_active) { if (!is_active) {
join(account, new Jid(conference.jid), conference.nick, conference.password); join(account, conference.jid, conference.nick, conference.password);
} }
} }
} }
private void set_autojoin(Core.XmppStream stream, Jid jid, string? nick, string? password) { private void set_autojoin(XmppStream stream, Jid jid, string? nick, string? password) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => { stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
Xep.Bookmarks.Conference changed = new Xep.Bookmarks.Conference(jid.to_string()) { nick=nick, password=password, autojoin=true }; if (conferences == null) return;
Xep.Bookmarks.Conference changed = new Xep.Bookmarks.Conference(jid) { nick=nick, password=password, autojoin=true };
foreach (Xep.Bookmarks.Conference conference in conferences) { foreach (Xep.Bookmarks.Conference conference in conferences) {
if (conference.jid == jid.bare_jid.to_string() && conference.nick == nick && conference.password == password) { if (conference.jid.equals_bare(jid) && conference.nick == nick && conference.password == password) {
if (!conference.autojoin) { if (!conference.autojoin) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).replace_conference(stream, conference, changed); stream.get_module(Xep.Bookmarks.Module.IDENTITY).replace_conference(stream, conference, changed);
} }
@ -315,10 +305,11 @@ public class MucManager : StreamInteractionModule, Object {
}); });
} }
private void unset_autojoin(Core.XmppStream stream, Jid jid) { private void unset_autojoin(XmppStream stream, Jid jid) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => { stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
if (conferences == null) return;
foreach (Xep.Bookmarks.Conference conference in conferences) { foreach (Xep.Bookmarks.Conference conference in conferences) {
if (conference.jid == jid.bare_jid.to_string()) { if (conference.jid.equals_bare(jid)) {
if (conference.autojoin) { if (conference.autojoin) {
Xep.Bookmarks.Conference change = new Xep.Bookmarks.Conference(conference.jid) { nick=conference.nick, password=conference.password, autojoin=false }; Xep.Bookmarks.Conference change = new Xep.Bookmarks.Conference(conference.jid) { nick=conference.nick, password=conference.password, autojoin=false };
stream.get_module(Xep.Bookmarks.Module.IDENTITY).replace_conference(stream, conference, change); stream.get_module(Xep.Bookmarks.Module.IDENTITY).replace_conference(stream, conference, change);

View file

@ -27,9 +27,9 @@ public class PresenceManager : StreamInteractionModule, Object {
} }
public Show get_last_show(Jid jid, Account account) { public Show get_last_show(Jid jid, Account account) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
Xmpp.Presence.Stanza? presence = stream.get_flag(Presence.Flag.IDENTITY).get_presence(jid.to_string()); Xmpp.Presence.Stanza? presence = stream.get_flag(Presence.Flag.IDENTITY).get_presence(jid);
if (presence != null) { if (presence != null) {
return new Show(jid, presence.show, new DateTime.now_utc()); return new Show(jid, presence.show, new DateTime.now_utc());
} }
@ -41,20 +41,12 @@ public class PresenceManager : StreamInteractionModule, Object {
return shows[jid]; return shows[jid];
} }
public ArrayList<Jid>? get_full_jids(Jid jid, Account account) { public Gee.List<Jid>? get_full_jids(Jid jid, Account account) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
Xmpp.Presence.Flag flag = stream.get_flag(Presence.Flag.IDENTITY); Xmpp.Presence.Flag flag = stream.get_flag(Presence.Flag.IDENTITY);
if (flag == null) return null; if (flag == null) return null;
Gee.List<string>? resources = flag.get_resources(jid.bare_jid.to_string()); return flag.get_resources(jid.bare_jid);
if (resources == null) {
return null;
}
ArrayList<Jid> ret = new ArrayList<Jid>(Jid.equals_func);
foreach (string resource in resources) {
ret.add(new Jid(resource));
}
return ret;
} }
return null; return null;
} }
@ -64,40 +56,39 @@ public class PresenceManager : StreamInteractionModule, Object {
} }
public void request_subscription(Account account, Jid jid) { public void request_subscription(Account account, Jid jid) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xmpp.Presence.Module.IDENTITY).request_subscription(stream, jid.bare_jid.to_string()); if (stream != null) stream.get_module(Xmpp.Presence.Module.IDENTITY).request_subscription(stream, jid.bare_jid);
} }
public void approve_subscription(Account account, Jid jid) { public void approve_subscription(Account account, Jid jid) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
stream.get_module(Xmpp.Presence.Module.IDENTITY).approve_subscription(stream, jid.bare_jid.to_string()); stream.get_module(Xmpp.Presence.Module.IDENTITY).approve_subscription(stream, jid.bare_jid);
subscription_requests.remove(jid); subscription_requests.remove(jid);
} }
} }
public void deny_subscription(Account account, Jid jid) { public void deny_subscription(Account account, Jid jid) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
if (stream != null) { if (stream != null) {
stream.get_module(Xmpp.Presence.Module.IDENTITY).deny_subscription(stream, jid.bare_jid.to_string()); stream.get_module(Xmpp.Presence.Module.IDENTITY).deny_subscription(stream, jid.bare_jid);
subscription_requests.remove(jid); subscription_requests.remove(jid);
} }
} }
public void cancel_subscription(Account account, Jid jid) { public void cancel_subscription(Account account, Jid jid) {
Core.XmppStream stream = stream_interactor.get_stream(account); XmppStream stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xmpp.Presence.Module.IDENTITY).cancel_subscription(stream, jid.bare_jid.to_string()); if (stream != null) stream.get_module(Xmpp.Presence.Module.IDENTITY).cancel_subscription(stream, jid.bare_jid);
} }
private void on_account_added(Account account) { private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_available_show.connect((stream, jid, show) => stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_available_show.connect((stream, jid, show) =>
on_received_available_show(account, new Jid(jid), show) on_received_available_show(account, jid, show)
); );
stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_unavailable.connect((stream, presence) => stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_unavailable.connect((stream, presence) =>
on_received_unavailable(account, new Jid(presence.from)) on_received_unavailable(account, presence.from)
); );
stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_subscription_request.connect((stream, jid_str) => { stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_subscription_request.connect((stream, jid) => {
Jid jid = new Jid(jid_str);
if (!subscription_requests.contains(jid)) { if (!subscription_requests.contains(jid)) {
subscription_requests.add(jid); subscription_requests.add(jid);
} }

View file

@ -40,18 +40,18 @@ public class RosterManager : StreamInteractionModule, Object {
} }
public void remove_jid(Account account, Jid jid) { public void remove_jid(Account account, Jid jid) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xmpp.Roster.Module.IDENTITY).remove_jid(stream, jid.bare_jid.to_string()); if (stream != null) stream.get_module(Xmpp.Roster.Module.IDENTITY).remove_jid(stream, jid.bare_jid);
} }
public void add_jid(Account account, Jid jid, string? handle) { public void add_jid(Account account, Jid jid, string? handle) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xmpp.Roster.Module.IDENTITY).add_jid(stream, jid.bare_jid.to_string(), handle); if (stream != null) stream.get_module(Xmpp.Roster.Module.IDENTITY).add_jid(stream, jid.bare_jid, handle);
} }
public void set_jid_handle(Account account, Jid jid, string? handle) { public void set_jid_handle(Account account, Jid jid, string? handle) {
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xmpp.Roster.Module.IDENTITY).set_jid_handle(stream, jid.bare_jid.to_string(), handle); if (stream != null) stream.get_module(Xmpp.Roster.Module.IDENTITY).set_jid_handle(stream, jid.bare_jid, handle);
} }
private void on_account_added(Account account) { private void on_account_added(Account account) {
@ -61,7 +61,7 @@ public class RosterManager : StreamInteractionModule, Object {
} }
}); });
stream_interactor.module_manager.get_module(account, Roster.Module.IDENTITY).item_removed.connect( (stream, roster_item) => { stream_interactor.module_manager.get_module(account, Roster.Module.IDENTITY).item_removed.connect( (stream, roster_item) => {
removed_roster_item(account, new Jid(roster_item.jid), roster_item); removed_roster_item(account, roster_item.jid, roster_item);
}); });
stream_interactor.module_manager.get_module(account, Roster.Module.IDENTITY).item_updated.connect( (stream, roster_item) => { stream_interactor.module_manager.get_module(account, Roster.Module.IDENTITY).item_updated.connect( (stream, roster_item) => {
on_roster_item_updated(account, roster_item); on_roster_item_updated(account, roster_item);
@ -69,7 +69,7 @@ public class RosterManager : StreamInteractionModule, Object {
} }
private void on_roster_item_updated(Account account, Roster.Item roster_item) { private void on_roster_item_updated(Account account, Roster.Item roster_item) {
updated_roster_item(account, new Jid(roster_item.jid), roster_item); updated_roster_item(account, roster_item.jid, roster_item);
} }
} }
@ -77,7 +77,7 @@ public class RosterStoreImpl : Roster.Storage, Object {
private Account account; private Account account;
private Database db; private Database db;
private HashMap<string, Roster.Item> items = new HashMap<string, Roster.Item>(); private HashMap<Jid, Roster.Item> items = new HashMap<Jid, Roster.Item>(Jid.hash_bare_func, Jid.equals_bare_func);
public class RosterStoreImpl(Account account, Database db) { public class RosterStoreImpl(Account account, Database db) {
this.account = account; this.account = account;
@ -85,7 +85,7 @@ public class RosterStoreImpl : Roster.Storage, Object {
foreach (Qlite.Row row in db.roster.select().with(db.roster.account_id, "=", account.id)) { foreach (Qlite.Row row in db.roster.select().with(db.roster.account_id, "=", account.id)) {
Roster.Item item = new Roster.Item(); Roster.Item item = new Roster.Item();
item.jid = row[db.roster.jid]; item.jid = Jid.parse(row[db.roster.jid]);
item.name = row[db.roster.handle]; item.name = row[db.roster.handle];
item.subscription = row[db.roster.subscription]; item.subscription = row[db.roster.subscription];
items[item.jid] = item; items[item.jid] = item;
@ -101,7 +101,7 @@ public class RosterStoreImpl : Roster.Storage, Object {
} }
public Roster.Item? get_item(Jid jid) { public Roster.Item? get_item(Jid jid) {
return items.has_key(jid.bare_jid.to_string()) ? items[jid.bare_jid.to_string()] : null; return items.has_key(jid) ? items[jid] : null;
} }
public void set_roster_version(string version) { public void set_roster_version(string version) {
@ -119,7 +119,7 @@ public class RosterStoreImpl : Roster.Storage, Object {
items[item.jid] = item; items[item.jid] = item;
db.roster.insert().or("REPLACE") db.roster.insert().or("REPLACE")
.value(db.roster.account_id, account.id) .value(db.roster.account_id, account.id)
.value(db.roster.jid, item.jid) .value(db.roster.jid, item.jid.to_string())
.value(db.roster.handle, item.name) .value(db.roster.handle, item.name)
.value(db.roster.subscription, item.subscription) .value(db.roster.subscription, item.subscription)
.perform(); .perform();
@ -129,7 +129,7 @@ public class RosterStoreImpl : Roster.Storage, Object {
items.unset(item.jid); items.unset(item.jid);
db.roster.delete() db.roster.delete()
.with(db.roster.account_id, "=", account.id) .with(db.roster.account_id, "=", account.id)
.with(db.roster.jid, "=", item.jid).perform(); .with(db.roster.jid, "=", item.jid.to_string()).perform();
} }
} }

View file

@ -9,8 +9,8 @@ public class StreamInteractor {
public signal void account_added(Account account); public signal void account_added(Account account);
public signal void account_removed(Account account); public signal void account_removed(Account account);
public signal void stream_negotiated(Account account, Core.XmppStream stream); public signal void stream_negotiated(Account account, XmppStream stream);
public signal void attached_modules(Account account, Core.XmppStream stream); public signal void attached_modules(Account account, XmppStream stream);
public ModuleManager module_manager; public ModuleManager module_manager;
public ConnectionManager connection_manager; public ConnectionManager connection_manager;
@ -42,7 +42,7 @@ public class StreamInteractor {
return ret; return ret;
} }
public Core.XmppStream? get_stream(Account account) { public XmppStream? get_stream(Account account) {
return connection_manager.get_stream(account); return connection_manager.get_stream(account);
} }
@ -58,7 +58,7 @@ public class StreamInteractor {
return null; return null;
} }
private void on_stream_opened(Account account, Core.XmppStream stream) { private void on_stream_opened(Account account, XmppStream stream) {
stream.stream_negotiated.connect( (stream) => { stream.stream_negotiated.connect( (stream) => {
stream_negotiated(account, stream); stream_negotiated(account, stream);
}); });

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {
@ -122,7 +123,7 @@ public class AddConferenceDialog : Gtk.Dialog {
ConferenceListRow? conference_row = conference_list.get_selected_row() as ConferenceListRow; ConferenceListRow? conference_row = conference_list.get_selected_row() as ConferenceListRow;
if (conference_row != null) { if (conference_row != null) {
details_fragment.account = conference_row.account; details_fragment.account = conference_row.account;
details_fragment.jid = conference_row.bookmark.jid; details_fragment.jid = conference_row.bookmark.jid.to_string();
details_fragment.nick = conference_row.bookmark.nick; details_fragment.nick = conference_row.bookmark.nick;
if (conference_row.bookmark.password != null) details_fragment.password = conference_row.bookmark.password; if (conference_row.bookmark.password != null) details_fragment.password = conference_row.bookmark.password;
ok_button.grab_focus(); ok_button.grab_focus();

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {
@ -43,7 +44,7 @@ protected class AddGroupchatDialog : Gtk.Dialog {
accounts_stack.set_visible_child_name("label"); accounts_stack.set_visible_child_name("label");
account_label.label = account.bare_jid.to_string(); account_label.label = account.bare_jid.to_string();
account_combobox.selected = account; account_combobox.selected = account;
jid_entry.text = conference.jid; jid_entry.text = conference.jid.to_string();
nick_entry.text = conference.nick ?? ""; nick_entry.text = conference.nick ?? "";
alias_entry.text = conference.name; alias_entry.text = conference.name;
} }
@ -64,7 +65,7 @@ protected class AddGroupchatDialog : Gtk.Dialog {
} }
private void on_ok_button_clicked() { private void on_ok_button_clicked() {
Xmpp.Xep.Bookmarks.Conference conference = new Xmpp.Xep.Bookmarks.Conference(jid_entry.text); Xmpp.Xep.Bookmarks.Conference conference = new Xmpp.Xep.Bookmarks.Conference(Jid.parse(jid_entry.text));
conference.nick = nick_entry.text != "" ? nick_entry.text : null; conference.nick = nick_entry.text != "" ? nick_entry.text : null;
conference.name = alias_entry.text; conference.name = alias_entry.text;
if (edit_conference == null) { if (edit_conference == null) {

View file

@ -2,6 +2,7 @@ using Gdk;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {

View file

@ -39,8 +39,12 @@ protected class ConferenceList : FilterableList {
} }
} }
private void on_conference_bookmarks_received(Core.XmppStream stream, Account account, Gee.List<Xep.Bookmarks.Conference> conferences) { private void on_conference_bookmarks_received(XmppStream stream, Account account, Gee.List<Xep.Bookmarks.Conference>? conferences) {
lists[account] = conferences; if (conferences == null) {
lists.unset(account);
} else {
lists[account] = conferences;
}
refresh_conferences(); refresh_conferences();
} }
@ -77,15 +81,15 @@ internal class ConferenceListRow : ListRow {
public Xep.Bookmarks.Conference bookmark; public Xep.Bookmarks.Conference bookmark;
public ConferenceListRow(StreamInteractor stream_interactor, Xep.Bookmarks.Conference bookmark, Account account) { public ConferenceListRow(StreamInteractor stream_interactor, Xep.Bookmarks.Conference bookmark, Account account) {
this.jid = new Jid(bookmark.jid); this.jid = bookmark.jid;
this.account = account; this.account = account;
this.bookmark = bookmark; this.bookmark = bookmark;
name_label.label = bookmark.name ?? bookmark.jid; name_label.label = bookmark.name ?? bookmark.jid.to_string();
if (stream_interactor.get_accounts().size > 1) { if (stream_interactor.get_accounts().size > 1) {
via_label.label = "via " + account.bare_jid.to_string(); via_label.label = "via " + account.bare_jid.to_string();
} else if (bookmark.name != null && bookmark.name != bookmark.jid) { } else if (bookmark.name != null && bookmark.name != bookmark.jid.to_string()) {
via_label.label = bookmark.jid; via_label.label = bookmark.jid.to_string();
} else { } else {
via_label.visible = false; via_label.visible = false;
} }

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {

View file

@ -49,7 +49,7 @@ protected class RosterList : FilterableList {
private void on_updated_roster_item(Account account, Jid jid, Roster.Item roster_item) { private void on_updated_roster_item(Account account, Jid jid, Roster.Item roster_item) {
on_removed_roster_item(account, jid, roster_item); on_removed_roster_item(account, jid, roster_item);
ListRow row = new ListRow.from_jid(stream_interactor, new Jid(roster_item.jid), account, accounts.size > 1); ListRow row = new ListRow.from_jid(stream_interactor, roster_item.jid, account, accounts.size > 1);
rows[account][jid] = row; rows[account][jid] = row;
add(row); add(row);
invalidate_sort(); invalidate_sort();
@ -59,7 +59,7 @@ protected class RosterList : FilterableList {
private void fetch_roster_items(Account account) { private void fetch_roster_items(Account account) {
rows[account] = new HashMap<Jid, ListRow>(Jid.hash_func, Jid.equals_func); rows[account] = new HashMap<Jid, ListRow>(Jid.hash_func, Jid.equals_func);
foreach (Roster.Item roster_item in stream_interactor.get_module(RosterManager.IDENTITY).get_roster(account)) { foreach (Roster.Item roster_item in stream_interactor.get_module(RosterManager.IDENTITY).get_roster(account)) {
on_updated_roster_item(account, new Jid(roster_item.jid), roster_item); on_updated_roster_item(account, roster_item.jid, roster_item);
} }
} }

View file

@ -3,6 +3,7 @@ using Gdk;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {

View file

@ -2,6 +2,7 @@ using Gtk;
using Dino.Entities; using Dino.Entities;
using Dino.Ui; using Dino.Ui;
using Xmpp;
public class Dino.Ui.Application : Gtk.Application, Dino.Application { public class Dino.Ui.Application : Gtk.Application, Dino.Application {
private Notifications notifications; private Notifications notifications;

View file

@ -4,6 +4,7 @@ using Gdk;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui { namespace Dino.Ui {
@ -109,7 +110,7 @@ public class AvatarGenerator {
} }
private Pixbuf draw_groupchat_tile(Jid jid, Account account, int width, int height) { private Pixbuf draw_groupchat_tile(Jid jid, Account account, int width, int height) {
ArrayList<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account); Gee.List<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account);
if (stateless || occupants == null || occupants.size == 0) { if (stateless || occupants == null || occupants.size == 0) {
return draw_chat_tile(jid, account, width, height); return draw_chat_tile(jid, account, width, height);
} }

View file

@ -10,6 +10,7 @@ public class EncryptionButton : MenuButton {
private Conversation? conversation; private Conversation? conversation;
private RadioButton? button_unencrypted; private RadioButton? button_unencrypted;
private Map<RadioButton, Plugins.EncryptionListEntry> encryption_radios = new HashMap<RadioButton, Plugins.EncryptionListEntry>(); private Map<RadioButton, Plugins.EncryptionListEntry> encryption_radios = new HashMap<RadioButton, Plugins.EncryptionListEntry>();
private string? current_icon;
public EncryptionButton() { public EncryptionButton() {
relief = ReliefStyle.NONE; relief = ReliefStyle.NONE;
@ -56,14 +57,17 @@ public class EncryptionButton : MenuButton {
} }
} }
private void update_encryption_menu_icon() { private void set_icon(string icon) {
if (conversation.encryption == Encryption.NONE) { if (icon != current_icon) {
set_image(new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON)); image = new Image.from_icon_name(icon, IconSize.BUTTON);
} else { current_icon = icon;
set_image(new Image.from_icon_name("changes-prevent-symbolic", IconSize.BUTTON));
} }
} }
private void update_encryption_menu_icon() {
set_icon(conversation.encryption == Encryption.NONE ? "changes-allow-symbolic" : "changes-prevent-symbolic");
}
public new void set_conversation(Conversation conversation) { public new void set_conversation(Conversation conversation) {
this.conversation = conversation; this.conversation = conversation;
update_encryption_menu_state(); update_encryption_menu_state();

View file

@ -3,6 +3,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ChatInput { namespace Dino.Ui.ChatInput {

View file

@ -84,8 +84,8 @@ public class View : Box {
stream_interactor.get_module(MucManager.IDENTITY).change_nick(conversation.account, conversation.counterpart, token[1]); stream_interactor.get_module(MucManager.IDENTITY).change_nick(conversation.account, conversation.counterpart, token[1]);
return; return;
case "/ping": case "/ping":
Xmpp.Core.XmppStream? stream = stream_interactor.get_stream(conversation.account); Xmpp.XmppStream? stream = stream_interactor.get_stream(conversation.account);
stream.get_module(Xmpp.Xep.Ping.Module.IDENTITY).send_ping(stream, conversation.counterpart.to_string() + "/" + token[1], null); stream.get_module(Xmpp.Xep.Ping.Module.IDENTITY).send_ping(stream, conversation.counterpart.with_resource(token[1]), null);
return; return;
case "/topic": case "/topic":
stream_interactor.get_module(MucManager.IDENTITY).change_subject(conversation.account, conversation.counterpart, token[1]); stream_interactor.get_module(MucManager.IDENTITY).change_subject(conversation.account, conversation.counterpart, token[1]);

View file

@ -17,7 +17,7 @@ public class MucConfigFormProvider : Plugins.ContactDetailsProvider, Object {
public void populate(Conversation conversation, Plugins.ContactDetails contact_details, Plugins.WidgetType type) { public void populate(Conversation conversation, Plugins.ContactDetails contact_details, Plugins.WidgetType type) {
if (type != Plugins.WidgetType.GTK) return; if (type != Plugins.WidgetType.GTK) return;
if (conversation.type_ == Conversation.Type.GROUPCHAT) { if (conversation.type_ == Conversation.Type.GROUPCHAT) {
Xmpp.Core.XmppStream? stream = stream_interactor.get_stream(conversation.account); Xmpp.XmppStream? stream = stream_interactor.get_stream(conversation.account);
if (stream == null) return; if (stream == null) return;
stream_interactor.get_module(MucManager.IDENTITY).get_config_form(conversation.account, conversation.counterpart, (jid, data_form) => { stream_interactor.get_module(MucManager.IDENTITY).get_config_form(conversation.account, conversation.counterpart, (jid, data_form) => {
contact_details.save.connect(() => { data_form.submit(); }); contact_details.save.connect(() => { data_form.submit(); });

View file

@ -3,6 +3,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ConversationSelector { namespace Dino.Ui.ConversationSelector {
@ -18,7 +19,6 @@ public class ChatRow : ConversationRow {
stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect((account, jid, roster_item) => { stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect((account, jid, roster_item) => {
if (conversation.account.equals(account) && conversation.counterpart.equals(jid)) { if (conversation.account.equals(account) && conversation.counterpart.equals(jid)) {
update_name_label(); update_name_label();
update_avatar();
} }
}); });
} }
@ -41,7 +41,7 @@ public class ChatRow : ConversationRow {
jid_label.label = conversation.counterpart.to_string(); jid_label.label = conversation.counterpart.to_string();
ArrayList<Jid>? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(conversation.counterpart, conversation.account); Gee.List<Jid>? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(conversation.counterpart, conversation.account);
if (full_jids != null) { if (full_jids != null) {
for (int i = 0; i < full_jids.size; i++) { for (int i = 0; i < full_jids.size; i++) {
inner_box.add(get_fulljid_box(full_jids[i])); inner_box.add(get_fulljid_box(full_jids[i]));

View file

@ -4,6 +4,7 @@ using Gtk;
using Pango; using Pango;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ConversationSelector { namespace Dino.Ui.ConversationSelector {

View file

@ -15,7 +15,6 @@ public class GroupchatPmRow : ConversationRow {
tooltip.set_custom(generate_tooltip()); tooltip.set_custom(generate_tooltip());
return true; return true;
}); });
update_avatar();
} }
protected override void update_message_label() { protected override void update_message_label() {

View file

@ -8,12 +8,10 @@ public class GroupchatRow : ConversationRow {
base(stream_interactor, conversation); base(stream_interactor, conversation);
has_tooltip = true; has_tooltip = true;
set_tooltip_text(conversation.counterpart.bare_jid.to_string()); set_tooltip_text(conversation.counterpart.bare_jid.to_string());
update_avatar();
closed.connect(() => { closed.connect(() => {
stream_interactor.get_module(MucManager.IDENTITY).part(conversation.account, conversation.counterpart); stream_interactor.get_module(MucManager.IDENTITY).part(conversation.account, conversation.counterpart);
}); });
stream_interactor.get_module(MucManager.IDENTITY).left.connect(update_avatar);
} }
protected override void update_message_label() { protected override void update_message_label() {

View file

@ -26,18 +26,6 @@ public class List : ListBox {
stream_interactor.get_module(ConversationManager.IDENTITY).conversation_deactivated.connect(remove_conversation); stream_interactor.get_module(ConversationManager.IDENTITY).conversation_deactivated.connect(remove_conversation);
stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_message_received); stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_message_received);
stream_interactor.get_module(MessageProcessor.IDENTITY).message_sent.connect(on_message_received); stream_interactor.get_module(MessageProcessor.IDENTITY).message_sent.connect(on_message_received);
stream_interactor.get_module(PresenceManager.IDENTITY).show_received.connect((show, jid, account) => {
foreach (Conversation conversation in stream_interactor.get_module(ConversationManager.IDENTITY).get_conversations_for_presence(show, account)) {
if (rows.has_key(conversation)) rows[conversation].on_show_received(show);
}
});
stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.connect((avatar, jid, account) => {
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account);
if (conversation != null && rows.has_key(conversation)) {
ChatRow row = rows[conversation] as ChatRow;
if (row != null) row.update_avatar();
}
});
Timeout.add_seconds(60, () => { Timeout.add_seconds(60, () => {
foreach (ConversationRow row in rows.values) row.update(); foreach (ConversationRow row in rows.values) row.update();
return true; return true;
@ -99,7 +87,7 @@ public class List : ListBox {
row.closed.connect(() => { select_next_conversation(conversation); }); row.closed.connect(() => { select_next_conversation(conversation); });
row.main_revealer.set_reveal_child(true); row.main_revealer.set_reveal_child(true);
} }
invalidate_sort(); //invalidate_sort();
} }
private void select_next_conversation(Conversation conversation) { private void select_next_conversation(Conversation conversation) {

View file

@ -2,6 +2,7 @@ using Gdk;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ConversationSummary { namespace Dino.Ui.ConversationSummary {
@ -26,7 +27,7 @@ public class DefaultFileDisplay : Plugins.MetaConversationItem {
this.stream_interactor = stream_interactor; this.stream_interactor = stream_interactor;
this.file_transfer = file_transfer; this.file_transfer = file_transfer;
this.jid = file_transfer.direction == FileTransfer.DIRECTION_SENT ? new Jid.with_resource(file_transfer.account.bare_jid.to_string(), file_transfer.account.resourcepart) : file_transfer.counterpart; this.jid = file_transfer.direction == FileTransfer.DIRECTION_SENT ? file_transfer.account.bare_jid.with_resource(file_transfer.account.resourcepart) : file_transfer.counterpart;
this.sort_time = file_transfer.time; this.sort_time = file_transfer.time;
this.seccondary_sort_indicator = file_transfer.id + 0.2903; this.seccondary_sort_indicator = file_transfer.id + 0.2903;
this.display_time = file_transfer.time; this.display_time = file_transfer.time;

View file

@ -1,4 +1,5 @@
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ConversationSummary { namespace Dino.Ui.ConversationSummary {

View file

@ -1,6 +1,7 @@
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ConversationSummary { namespace Dino.Ui.ConversationSummary {
@ -25,7 +26,7 @@ public class ImageDisplay : Plugins.MetaConversationItem {
this.stream_interactor = stream_interactor; this.stream_interactor = stream_interactor;
this.file_transfer = file_transfer; this.file_transfer = file_transfer;
this.jid = file_transfer.direction == FileTransfer.DIRECTION_SENT ? new Jid.with_resource(file_transfer.account.bare_jid.to_string(), file_transfer.account.resourcepart) : file_transfer.counterpart; this.jid = file_transfer.direction == FileTransfer.DIRECTION_SENT ? file_transfer.account.bare_jid.with_resource(file_transfer.account.resourcepart) : file_transfer.counterpart;
this.sort_time = file_transfer.time; this.sort_time = file_transfer.time;
this.seccondary_sort_indicator = file_transfer.id + 0.2903; this.seccondary_sort_indicator = file_transfer.id + 0.2903;
this.display_time = file_transfer.time; this.display_time = file_transfer.time;

View file

@ -1,6 +1,7 @@
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ConversationSummary { namespace Dino.Ui.ConversationSummary {

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ManageAccounts { namespace Dino.Ui.ManageAccounts {

View file

@ -4,6 +4,7 @@ using Gtk;
using Markup; using Markup;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ManageAccounts { namespace Dino.Ui.ManageAccounts {

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.OccupantMenu{ namespace Dino.Ui.OccupantMenu{
@ -39,6 +40,7 @@ public class List : Box {
add_occupant(occupant); add_occupant(occupant);
} }
} }
list_box.invalidate_filter();
} }
private void refilter() { private void refilter() {
@ -57,8 +59,6 @@ public class List : Box {
public void add_occupant(Jid jid) { public void add_occupant(Jid jid) {
rows[jid] = new ListRow(stream_interactor, conversation.account, jid); rows[jid] = new ListRow(stream_interactor, conversation.account, jid);
list_box.add(rows[jid]); list_box.add(rows[jid]);
list_box.invalidate_filter();
list_box.invalidate_sort();
} }
public void remove_occupant(Jid jid) { public void remove_occupant(Jid jid) {
@ -77,6 +77,7 @@ public class List : Box {
} else if (show.as != Show.OFFLINE && !rows.has_key(jid)) { } else if (show.as != Show.OFFLINE && !rows.has_key(jid)) {
add_occupant(jid); add_occupant(jid);
} }
list_box.invalidate_filter();
} }
} }

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Ui.OccupantMenu { namespace Dino.Ui.OccupantMenu {
public class View : Popover { public class View : Popover {

View file

@ -65,7 +65,7 @@ public static string get_display_name(StreamInteractor stream_interactor, Jid ji
} }
return jid.resourcepart; return jid.resourcepart;
} else { } else {
if (jid.bare_jid.equals(account.bare_jid.bare_jid)) { if (jid.equals_bare(account.bare_jid)) {
if (account.alias == null || account.alias == "") { if (account.alias == null || account.alias == "") {
return account.bare_jid.to_string(); return account.bare_jid.to_string();
} else { } else {
@ -84,9 +84,24 @@ public static string get_message_display_name(StreamInteractor stream_interactor
return get_display_name(stream_interactor, message.from, account); return get_display_name(stream_interactor, message.from, account);
} }
public static void image_set_from_scaled_pixbuf(Image image, Gdk.Pixbuf pixbuf, int scale = 0) { public static void image_set_from_scaled_pixbuf(Image image, Gdk.Pixbuf pixbuf, int scale = 0, int width = 0, int height = 0) {
if (scale == 0) scale = image.scale_factor; if (scale == 0) scale = image.scale_factor;
image.set_from_surface(Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, image.get_window())); Cairo.Surface surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, image.get_window());
if (height == 0 && width != 0) {
height = (int) ((double) width / pixbuf.width * pixbuf.height);
} else if (height != 0 && width == 0) {
width = (int) ((double) height / pixbuf.height * pixbuf.width);
}
if (width != 0) {
Cairo.Surface surface_new = new Cairo.Surface.similar_image(surface, Cairo.Format.ARGB32, width, height);
Cairo.Context context = new Cairo.Context(surface_new);
context.scale((double) width * scale / pixbuf.width, (double) height * scale / pixbuf.height);
context.set_source_surface(surface, 0, 0);
context.get_source().set_filter(Cairo.Filter.BEST);
context.paint();
surface = surface_new;
}
image.set_from_surface(surface);
} }
private const string force_background_css = "%s { background-color: %s; }"; private const string force_background_css = "%s { background-color: %s; }";

View file

@ -2,6 +2,7 @@ using Gee;
using Gtk; using Gtk;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Plugins.HttpFiles { namespace Dino.Plugins.HttpFiles {

View file

@ -30,7 +30,7 @@ public class Manager : StreamInteractionModule, FileSender, Object {
} }
public void send_file(Conversation conversation, FileTransfer file_transfer) { public void send_file(Conversation conversation, FileTransfer file_transfer) {
Xmpp.Core.XmppStream? stream = stream_interactor.get_stream(file_transfer.account); Xmpp.XmppStream? stream = stream_interactor.get_stream(file_transfer.account);
if (stream != null) { if (stream != null) {
stream_interactor.module_manager.get_module(file_transfer.account, UploadStreamModule.IDENTITY).upload(stream, file_transfer.input_stream, file_transfer.server_file_name, file_transfer.size, file_transfer.mime_type, stream_interactor.module_manager.get_module(file_transfer.account, UploadStreamModule.IDENTITY).upload(stream, file_transfer.input_stream, file_transfer.server_file_name, file_transfer.size, file_transfer.mime_type,
(stream, url_down) => { (stream, url_down) => {
@ -60,7 +60,7 @@ public class Manager : StreamInteractionModule, FileSender, Object {
} }
} }
private void on_stream_negotiated(Account account, Core.XmppStream stream) { private void on_stream_negotiated(Account account, XmppStream stream) {
stream_interactor.module_manager.get_module(account, UploadStreamModule.IDENTITY).feature_available.connect((stream, max_file_size) => { stream_interactor.module_manager.get_module(account, UploadStreamModule.IDENTITY).feature_available.connect((stream, max_file_size) => {
lock (max_file_sizes) { lock (max_file_sizes) {
max_file_sizes[account] = max_file_size; max_file_sizes[account] = max_file_size;
@ -69,7 +69,7 @@ public class Manager : StreamInteractionModule, FileSender, Object {
}); });
} }
private void check_add_oob(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) { private void check_add_oob(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation) {
if (message_is_file(db, message)) { if (message_is_file(db, message)) {
Xep.OutOfBandData.add_url_to_message(message_stanza, message_stanza.body); Xep.OutOfBandData.add_url_to_message(message_stanza, message_stanza.body);
} }

View file

@ -1,5 +1,5 @@
using Xmpp; using Xmpp;
using Xmpp.Core; using Xmpp;
using Xmpp.Xep; using Xmpp.Xep;
namespace Dino.Plugins.HttpFiles { namespace Dino.Plugins.HttpFiles {
@ -8,7 +8,7 @@ private const string NS_URI = "urn:xmpp:http:upload";
private const string NS_URI_0 = "urn:xmpp:http:upload:0"; private const string NS_URI_0 = "urn:xmpp:http:upload:0";
public class UploadStreamModule : XmppStreamModule { public class UploadStreamModule : XmppStreamModule {
public static Core.ModuleIdentity<UploadStreamModule> IDENTITY = new Core.ModuleIdentity<UploadStreamModule>(NS_URI, "0363_http_file_upload"); public static Xmpp.ModuleIdentity<UploadStreamModule> IDENTITY = new Xmpp.ModuleIdentity<UploadStreamModule>(NS_URI, "0363_http_file_upload");
public signal void feature_available(XmppStream stream, long max_file_size); public signal void feature_available(XmppStream stream, long max_file_size);
@ -116,7 +116,7 @@ public class UploadStreamModule : XmppStreamModule {
}); });
} }
private bool check_ns_in_info(XmppStream stream, string jid, Xep.ServiceDiscovery.InfoResult info_result) { private bool check_ns_in_info(XmppStream stream, Jid jid, Xep.ServiceDiscovery.InfoResult info_result) {
bool ver_available = false; bool ver_available = false;
bool ver_0_available = false; bool ver_0_available = false;
foreach (string feature in info_result.features) { foreach (string feature in info_result.features) {
@ -162,11 +162,11 @@ public class UploadStreamModule : XmppStreamModule {
public class Flag : XmppStreamFlag { public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "service_discovery"); public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "service_discovery");
public string file_store_jid; public Jid file_store_jid;
public string ns_ver; public string ns_ver;
public int? max_file_size; public int? max_file_size;
public Flag(string file_store_jid, string ns_ver) { public Flag(Jid file_store_jid, string ns_ver) {
this.file_store_jid = file_store_jid; this.file_store_jid = file_store_jid;
this.ns_ver = ns_ver; this.ns_ver = ns_ver;
} }

View file

@ -1,6 +1,6 @@
using Gee; using Gee;
using Signal; using Signal;
using Xmpp.Core; using Xmpp;
namespace Dino.Plugins.Omemo { namespace Dino.Plugins.Omemo {

View file

@ -69,16 +69,16 @@ public class Manager : StreamInteractionModule, Object {
stream_interactor.get_module(MessageProcessor.IDENTITY).pre_message_send.connect(on_pre_message_send); stream_interactor.get_module(MessageProcessor.IDENTITY).pre_message_send.connect(on_pre_message_send);
} }
private void on_pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) { private void on_pre_message_received(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation) {
MessageFlag? flag = MessageFlag.get_flag(message_stanza); MessageFlag? flag = MessageFlag.get_flag(message_stanza);
if (flag != null && ((!)flag).decrypted) { if (flag != null && ((!)flag).decrypted) {
message.encryption = Encryption.OMEMO; message.encryption = Encryption.OMEMO;
} }
} }
private void on_pre_message_send(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) { private void on_pre_message_send(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation) {
if (message.encryption == Encryption.OMEMO) { if (message.encryption == Encryption.OMEMO) {
Core.XmppStream? stream = stream_interactor.get_stream(conversation.account); XmppStream? stream = stream_interactor.get_stream(conversation.account);
if (stream == null) { if (stream == null) {
message.marked = Entities.Message.Marked.UNSENT; message.marked = Entities.Message.Marked.UNSENT;
return; return;
@ -89,7 +89,7 @@ public class Manager : StreamInteractionModule, Object {
return; return;
} }
StreamModule module = (!)module_; StreamModule module = (!)module_;
EncryptState enc_state = module.encrypt(message_stanza, conversation.account.bare_jid.to_string()); EncryptState enc_state = module.encrypt(message_stanza, conversation.account.bare_jid);
MessageState state; MessageState state;
lock (message_states) { lock (message_states) {
if (message_states.has_key(message)) { if (message_states.has_key(message)) {
@ -111,13 +111,13 @@ public class Manager : StreamInteractionModule, Object {
if (Plugin.DEBUG) print(@"OMEMO: message will be delayed: $state\n"); if (Plugin.DEBUG) print(@"OMEMO: message will be delayed: $state\n");
if (state.waiting_own_sessions > 0) { if (state.waiting_own_sessions > 0) {
module.start_sessions_with((!)stream, conversation.account.bare_jid.to_string()); module.start_sessions_with((!)stream, conversation.account.bare_jid);
} }
if (state.waiting_other_sessions > 0 && message.counterpart != null) { if (state.waiting_other_sessions > 0 && message.counterpart != null) {
module.start_sessions_with((!)stream, ((!)message.counterpart).bare_jid.to_string()); module.start_sessions_with((!)stream, ((!)message.counterpart).bare_jid);
} }
if (state.waiting_other_devicelist && message.counterpart != null) { if (state.waiting_other_devicelist && message.counterpart != null) {
module.request_user_devicelist((!)stream, ((!)message.counterpart).bare_jid.to_string()); module.request_user_devicelist((!)stream, ((!)message.counterpart).bare_jid);
} }
} }
} }
@ -132,20 +132,20 @@ public class Manager : StreamInteractionModule, Object {
stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).session_start_failed.connect((jid, device_id) => on_session_started(account, jid, true)); stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).session_start_failed.connect((jid, device_id) => on_session_started(account, jid, true));
} }
private void on_stream_negotiated(Account account, Core.XmppStream stream) { private void on_stream_negotiated(Account account, XmppStream stream) {
stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).request_user_devicelist(stream, account.bare_jid.to_string()); stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).request_user_devicelist(stream, account.bare_jid);
} }
private void on_session_started(Account account, string jid, bool failed) { private void on_session_started(Account account, Jid jid, bool failed) {
if (Plugin.DEBUG) print(@"OMEMO: session start between $(account.bare_jid) and $jid $(failed ? "failed" : "successful")\n"); if (Plugin.DEBUG) print(@"OMEMO: session start between $(account.bare_jid) and $jid $(failed ? "failed" : "successful")\n");
HashSet<Entities.Message> send_now = new HashSet<Entities.Message>(); HashSet<Entities.Message> send_now = new HashSet<Entities.Message>();
lock (message_states) { lock (message_states) {
foreach (Entities.Message msg in message_states.keys) { foreach (Entities.Message msg in message_states.keys) {
if (!msg.account.equals(account)) continue; if (!msg.account.equals(account)) continue;
MessageState state = message_states[msg]; MessageState state = message_states[msg];
if (account.bare_jid.to_string() == jid) { if (account.bare_jid.equals(jid)) {
state.waiting_own_sessions--; state.waiting_own_sessions--;
} else if (msg.counterpart != null && ((!)msg.counterpart).bare_jid.to_string() == jid) { } else if (msg.counterpart != null && msg.counterpart.equals_bare(jid)) {
state.waiting_other_sessions--; state.waiting_other_sessions--;
} }
if (state.should_retry_now()) { if (state.should_retry_now()) {
@ -162,16 +162,16 @@ public class Manager : StreamInteractionModule, Object {
} }
} }
private void on_device_list_loaded(Account account, string jid) { private void on_device_list_loaded(Account account, Jid jid) {
if (Plugin.DEBUG) print(@"OMEMO: received device list for $(account.bare_jid) from $jid\n"); if (Plugin.DEBUG) print(@"OMEMO: received device list for $(account.bare_jid) from $jid\n");
HashSet<Entities.Message> send_now = new HashSet<Entities.Message>(); HashSet<Entities.Message> send_now = new HashSet<Entities.Message>();
lock (message_states) { lock (message_states) {
foreach (Entities.Message msg in message_states.keys) { foreach (Entities.Message msg in message_states.keys) {
if (!msg.account.equals(account)) continue; if (!msg.account.equals(account)) continue;
MessageState state = message_states[msg]; MessageState state = message_states[msg];
if (account.bare_jid.to_string() == jid) { if (account.bare_jid.equals(jid)) {
state.waiting_own_devicelist = false; state.waiting_own_devicelist = false;
} else if (msg.counterpart != null && ((!)msg.counterpart).bare_jid.to_string() == jid) { } else if (msg.counterpart != null && msg.counterpart.equals_bare(jid)) {
state.waiting_other_devicelist = false; state.waiting_other_devicelist = false;
} }
if (state.should_retry_now()) { if (state.should_retry_now()) {
@ -188,7 +188,7 @@ public class Manager : StreamInteractionModule, Object {
} }
// Update meta database // Update meta database
Core.XmppStream? stream = stream_interactor.get_stream(account); XmppStream? stream = stream_interactor.get_stream(account);
if (stream == null) { if (stream == null) {
return; return;
} }
@ -197,10 +197,10 @@ public class Manager : StreamInteractionModule, Object {
return; return;
} }
ArrayList<int32> device_list = module.get_device_list(jid); ArrayList<int32> device_list = module.get_device_list(jid);
db.identity_meta.insert_device_list(jid, device_list); db.identity_meta.insert_device_list(jid.bare_jid.to_string(), device_list);
int inc = 0; int inc = 0;
foreach (Row row in db.identity_meta.with_address(jid).with_null(db.identity_meta.identity_key_public_base64)) { foreach (Row row in db.identity_meta.with_address(jid.bare_jid.to_string()).with_null(db.identity_meta.identity_key_public_base64)) {
module.fetch_bundle(stream, row[db.identity_meta.address_name], row[db.identity_meta.device_id]); module.fetch_bundle(stream, Jid.parse(row[db.identity_meta.address_name]), row[db.identity_meta.device_id]);
inc++; inc++;
} }
if (inc > 0) { if (inc > 0) {
@ -208,8 +208,8 @@ public class Manager : StreamInteractionModule, Object {
} }
} }
public void on_bundle_fetched(Account account, string jid, int32 device_id, Bundle bundle) { public void on_bundle_fetched(Account account, Jid jid, int32 device_id, Bundle bundle) {
db.identity_meta.insert_device_bundle(jid, device_id, bundle); db.identity_meta.insert_device_bundle(jid.bare_jid.to_string(), device_id, bundle);
} }
private void on_store_created(Account account, Store store) { private void on_store_created(Account account, Store store) {
@ -252,11 +252,11 @@ public class Manager : StreamInteractionModule, Object {
public bool can_encrypt(Entities.Conversation conversation) { public bool can_encrypt(Entities.Conversation conversation) {
Core.XmppStream? stream = stream_interactor.get_stream(conversation.account); XmppStream? stream = stream_interactor.get_stream(conversation.account);
if (stream == null) return false; if (stream == null) return false;
StreamModule? module = ((!)stream).get_module(StreamModule.IDENTITY); StreamModule? module = ((!)stream).get_module(StreamModule.IDENTITY);
if (module == null) return false; if (module == null) return false;
return ((!)module).is_known_address(conversation.counterpart.bare_jid.to_string()); return ((!)module).is_known_address(conversation.counterpart.bare_jid);
} }
public static void start(StreamInteractor stream_interactor, Database db) { public static void start(StreamInteractor stream_interactor, Database db) {

View file

@ -2,12 +2,12 @@ using Xmpp;
namespace Dino.Plugins.Omemo { namespace Dino.Plugins.Omemo {
public class MessageFlag : Message.MessageFlag { public class MessageFlag : Xmpp.MessageFlag {
public const string id = "omemo"; public const string id = "omemo";
public bool decrypted = false; public bool decrypted = false;
public static MessageFlag? get_flag(Message.Stanza message) { public static MessageFlag? get_flag(MessageStanza message) {
return (MessageFlag) message.get_flag(NS_URI, id); return (MessageFlag) message.get_flag(NS_URI, id);
} }

View file

@ -1,6 +1,6 @@
using Gee; using Gee;
using Xmpp; using Xmpp;
using Xmpp.Core; using Xmpp;
using Xmpp.Xep; using Xmpp.Xep;
using Signal; using Signal;
@ -14,33 +14,32 @@ private const string NODE_VERIFICATION = NS_URI + ".verification";
private const int NUM_KEYS_TO_PUBLISH = 100; private const int NUM_KEYS_TO_PUBLISH = 100;
public class StreamModule : XmppStreamModule { public class StreamModule : XmppStreamModule {
public static Core.ModuleIdentity<StreamModule> IDENTITY = new Core.ModuleIdentity<StreamModule>(NS_URI, "omemo_module"); public static Xmpp.ModuleIdentity<StreamModule> IDENTITY = new Xmpp.ModuleIdentity<StreamModule>(NS_URI, "omemo_module");
private Store store; private Store store;
private ConcurrentSet<string> active_bundle_requests = new ConcurrentSet<string>(); private ConcurrentSet<string> active_bundle_requests = new ConcurrentSet<string>();
private ConcurrentSet<string> active_devicelist_requests = new ConcurrentSet<string>(); private ConcurrentSet<Jid> active_devicelist_requests = new ConcurrentSet<Jid>();
private Map<string, ArrayList<int32>> device_lists = new HashMap<string, ArrayList<int32>>(); private Map<Jid, ArrayList<int32>> device_lists = new HashMap<Jid, ArrayList<int32>>(Jid.hash_bare_func, Jid.equals_bare_func);
private Map<string, ArrayList<int32>> ignored_devices = new HashMap<string, ArrayList<int32>>(); private Map<Jid, ArrayList<int32>> ignored_devices = new HashMap<Jid, ArrayList<int32>>(Jid.hash_bare_func, Jid.equals_bare_func);
private ReceivedPipelineListener received_pipeline_listener; private ReceivedPipelineListener received_pipeline_listener;
public signal void store_created(Store store); public signal void store_created(Store store);
public signal void device_list_loaded(string jid); public signal void device_list_loaded(Jid jid);
public signal void bundle_fetched(string jid, int device_id, Bundle bundle); public signal void bundle_fetched(Jid jid, int device_id, Bundle bundle);
public signal void session_started(string jid, int device_id); public signal void session_started(Jid jid, int device_id);
public signal void session_start_failed(string jid, int device_id); public signal void session_start_failed(Jid jid, int device_id);
public EncryptState encrypt(Message.Stanza message, string self_bare_jid) { public EncryptState encrypt(MessageStanza message, Jid self_jid) {
EncryptState status = new EncryptState(); EncryptState status = new EncryptState();
if (!Plugin.ensure_context()) return status; if (!Plugin.ensure_context()) return status;
if (message.to == null) return status; if (message.to == null) return status;
try { try {
string name = get_bare_jid((!)message.to); if (!device_lists.has_key(self_jid)) return status;
if (!device_lists.has_key(self_bare_jid)) return status;
status.own_list = true; status.own_list = true;
status.own_devices = device_lists.get(self_bare_jid).size; status.own_devices = device_lists.get(self_jid).size;
if (!device_lists.has_key(name)) return status; if (!device_lists.has_key(message.to)) return status;
status.other_list = true; status.other_list = true;
status.other_devices = device_lists.get(name).size; status.other_devices = device_lists.get(message.to).size;
if (status.own_devices == 0 || status.other_devices == 0) return status; if (status.own_devices == 0 || status.other_devices == 0) return status;
uint8[] key = new uint8[16]; uint8[] key = new uint8[16];
@ -59,9 +58,9 @@ public class StreamModule : XmppStreamModule {
.put_node(new StanzaNode.build("payload", NS_URI) .put_node(new StanzaNode.build("payload", NS_URI)
.put_node(new StanzaNode.text(Base64.encode(ciphertext)))); .put_node(new StanzaNode.text(Base64.encode(ciphertext))));
Address address = new Address(name, 0); Address address = new Address(message.to.bare_jid.to_string(), 0);
foreach(int32 device_id in device_lists[name]) { foreach(int32 device_id in device_lists[message.to]) {
if (is_ignored_device(name, device_id)) { if (is_ignored_device(message.to, device_id)) {
status.other_lost++; status.other_lost++;
continue; continue;
} }
@ -75,9 +74,9 @@ public class StreamModule : XmppStreamModule {
else status.other_failure++; else status.other_failure++;
} }
} }
address.name = self_bare_jid; address.name = self_jid.bare_jid.to_string();
foreach(int32 device_id in device_lists[self_bare_jid]) { foreach(int32 device_id in device_lists[self_jid]) {
if (is_ignored_device(self_bare_jid, device_id)) { if (is_ignored_device(self_jid, device_id)) {
status.own_lost++; status.own_lost++;
continue; continue;
} }
@ -119,26 +118,26 @@ public class StreamModule : XmppStreamModule {
this.store = Plugin.get_context().create_store(); this.store = Plugin.get_context().create_store();
store_created(store); store_created(store);
received_pipeline_listener = new ReceivedPipelineListener(store); received_pipeline_listener = new ReceivedPipelineListener(store);
stream.get_module(Message.Module.IDENTITY).received_pipeline.connect(received_pipeline_listener); stream.get_module(MessageModule.IDENTITY).received_pipeline.connect(received_pipeline_listener);
stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NODE_DEVICELIST, (stream, jid, id, node) => on_devicelist(stream, jid, id, node)); stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NODE_DEVICELIST, (stream, jid, id, node) => on_devicelist(stream, jid, id, node));
} }
public override void detach(XmppStream stream) { public override void detach(XmppStream stream) {
stream.get_module(Message.Module.IDENTITY).received_pipeline.disconnect(received_pipeline_listener); stream.get_module(MessageModule.IDENTITY).received_pipeline.disconnect(received_pipeline_listener);
} }
public void request_user_devicelist(XmppStream stream, string jid) { public void request_user_devicelist(XmppStream stream, Jid jid) {
if (active_devicelist_requests.add(jid)) { if (active_devicelist_requests.add(jid)) {
if (Plugin.DEBUG) print(@"OMEMO: requesting device list for $jid\n"); if (Plugin.DEBUG) print(@"OMEMO: requesting device list for $jid\n");
stream.get_module(Pubsub.Module.IDENTITY).request(stream, jid, NODE_DEVICELIST, (stream, jid, id, node) => on_devicelist(stream, jid, id, node)); stream.get_module(Pubsub.Module.IDENTITY).request(stream, jid, NODE_DEVICELIST, (stream, jid, id, node) => on_devicelist(stream, jid, id, node));
} }
} }
public void on_devicelist(XmppStream stream, string jid, string? id, StanzaNode? node_) { public void on_devicelist(XmppStream stream, Jid jid, string? id, StanzaNode? node_) {
StanzaNode node = node_ ?? new StanzaNode.build("list", NS_URI).add_self_xmlns(); StanzaNode node = node_ ?? new StanzaNode.build("list", NS_URI).add_self_xmlns();
string? my_jid = stream.get_flag(Bind.Flag.IDENTITY).my_jid; Jid? my_jid = stream.get_flag(Bind.Flag.IDENTITY).my_jid;
if (my_jid == null) return; if (my_jid == null) return;
if (jid == get_bare_jid((!)my_jid) && store.local_registration_id != 0) { if (jid.equals_bare(my_jid) && store.local_registration_id != 0) {
bool am_on_devicelist = false; bool am_on_devicelist = false;
foreach (StanzaNode device_node in node.get_subnodes("device")) { foreach (StanzaNode device_node in node.get_subnodes("device")) {
int device_id = device_node.get_attribute_int("id"); int device_id = device_node.get_attribute_int("id");
@ -164,17 +163,17 @@ public class StreamModule : XmppStreamModule {
device_list_loaded(jid); device_list_loaded(jid);
} }
public void start_sessions_with(XmppStream stream, string bare_jid) { public void start_sessions_with(XmppStream stream, Jid jid) {
if (!device_lists.has_key(bare_jid)) { if (!device_lists.has_key(jid)) {
return; return;
} }
Address address = new Address(bare_jid, 0); Address address = new Address(jid.bare_jid.to_string(), 0);
foreach(int32 device_id in device_lists[bare_jid]) { foreach(int32 device_id in device_lists[jid]) {
if (!is_ignored_device(bare_jid, device_id)) { if (!is_ignored_device(jid, device_id)) {
address.device_id = device_id; address.device_id = device_id;
try { try {
if (!store.contains_session(address)) { if (!store.contains_session(address)) {
start_session_with(stream, bare_jid, device_id); start_session_with(stream, jid, device_id);
} }
} catch (Error e) { } catch (Error e) {
// Ignore // Ignore
@ -184,25 +183,25 @@ public class StreamModule : XmppStreamModule {
address.device_id = 0; address.device_id = 0;
} }
public void start_session_with(XmppStream stream, string bare_jid, int device_id) { public void start_session_with(XmppStream stream, Jid jid, int device_id) {
if (active_bundle_requests.add(bare_jid + @":$device_id")) { if (active_bundle_requests.add(jid.bare_jid.to_string() + @":$device_id")) {
if (Plugin.DEBUG) print(@"OMEMO: Asking for bundle from $bare_jid:$device_id\n"); if (Plugin.DEBUG) print(@"OMEMO: Asking for bundle from $(jid.bare_jid.to_string()):$device_id\n");
stream.get_module(Pubsub.Module.IDENTITY).request(stream, bare_jid, @"$NODE_BUNDLES:$device_id", (stream, jid, id, node) => { stream.get_module(Pubsub.Module.IDENTITY).request(stream, jid.bare_jid, @"$NODE_BUNDLES:$device_id", (stream, jid, id, node) => {
on_other_bundle_result(stream, jid, device_id, id, node); on_other_bundle_result(stream, jid, device_id, id, node);
}); });
} }
} }
public void fetch_bundle(XmppStream stream, string bare_jid, int device_id) { public void fetch_bundle(XmppStream stream, Jid jid, int device_id) {
if (active_bundle_requests.add(bare_jid + @":$device_id")) { if (active_bundle_requests.add(jid.bare_jid.to_string() + @":$device_id")) {
if (Plugin.DEBUG) print(@"OMEMO: Asking for bundle from $bare_jid:$device_id\n"); if (Plugin.DEBUG) print(@"OMEMO: Asking for bundle from $(jid.bare_jid.to_string()):$device_id\n");
stream.get_module(Pubsub.Module.IDENTITY).request(stream, bare_jid, @"$NODE_BUNDLES:$device_id", (stream, jid, id, node) => { stream.get_module(Pubsub.Module.IDENTITY).request(stream, jid.bare_jid, @"$NODE_BUNDLES:$device_id", (stream, jid, id, node) => {
bundle_fetched(jid, device_id, new Bundle(node)); bundle_fetched(jid, device_id, new Bundle(node));
}); });
} }
} }
public ArrayList<int32> get_device_list(string jid) { public ArrayList<int32> get_device_list(Jid jid) {
if (is_known_address(jid)) { if (is_known_address(jid)) {
return device_lists[jid]; return device_lists[jid];
} else { } else {
@ -210,11 +209,11 @@ public class StreamModule : XmppStreamModule {
} }
} }
public bool is_known_address(string name) { public bool is_known_address(Jid jid) {
return device_lists.has_key(name); return device_lists.has_key(jid);
} }
public void ignore_device(string jid, int32 device_id) { public void ignore_device(Jid jid, int32 device_id) {
if (device_id <= 0) return; if (device_id <= 0) return;
lock (ignored_devices) { lock (ignored_devices) {
if (!ignored_devices.has_key(jid)) { if (!ignored_devices.has_key(jid)) {
@ -225,14 +224,14 @@ public class StreamModule : XmppStreamModule {
session_start_failed(jid, device_id); session_start_failed(jid, device_id);
} }
public bool is_ignored_device(string jid, int32 device_id) { public bool is_ignored_device(Jid jid, int32 device_id) {
if (device_id <= 0) return true; if (device_id <= 0) return true;
lock (ignored_devices) { lock (ignored_devices) {
return ignored_devices.has_key(jid) && ignored_devices[jid].contains(device_id); return ignored_devices.has_key(jid) && ignored_devices[jid].contains(device_id);
} }
} }
private void on_other_bundle_result(XmppStream stream, string jid, int device_id, string? id, StanzaNode? node) { private void on_other_bundle_result(XmppStream stream, Jid jid, int device_id, string? id, StanzaNode? node) {
bool fail = false; bool fail = false;
if (node == null) { if (node == null) {
// Device not registered, shouldn't exist // Device not registered, shouldn't exist
@ -255,7 +254,7 @@ public class StreamModule : XmppStreamModule {
if (pre_key_id < 0 || pre_key == null) { if (pre_key_id < 0 || pre_key == null) {
fail = true; fail = true;
} else { } else {
Address address = new Address(jid, device_id); Address address = new Address(jid.bare_jid.to_string(), device_id);
try { try {
if (store.contains_session(address)) { if (store.contains_session(address)) {
return; return;
@ -273,16 +272,16 @@ public class StreamModule : XmppStreamModule {
if (fail) { if (fail) {
stream.get_module(IDENTITY).ignore_device(jid, device_id); stream.get_module(IDENTITY).ignore_device(jid, device_id);
} }
stream.get_module(IDENTITY).active_bundle_requests.remove(jid + @":$device_id"); stream.get_module(IDENTITY).active_bundle_requests.remove(jid.bare_jid.to_string() + @":$device_id");
} }
public void publish_bundles_if_needed(XmppStream stream, string jid) { public void publish_bundles_if_needed(XmppStream stream, Jid jid) {
if (active_bundle_requests.add(jid + @":$(store.local_registration_id)")) { if (active_bundle_requests.add(jid.bare_jid.to_string() + @":$(store.local_registration_id)")) {
stream.get_module(Pubsub.Module.IDENTITY).request(stream, jid, @"$NODE_BUNDLES:$(store.local_registration_id)", on_self_bundle_result); stream.get_module(Pubsub.Module.IDENTITY).request(stream, jid, @"$NODE_BUNDLES:$(store.local_registration_id)", on_self_bundle_result);
} }
} }
private void on_self_bundle_result(XmppStream stream, string jid, string? id, StanzaNode? node) { private void on_self_bundle_result(XmppStream stream, Jid jid, string? id, StanzaNode? node) {
if (!Plugin.ensure_context()) return; if (!Plugin.ensure_context()) return;
Map<int, ECPublicKey> keys = new HashMap<int, ECPublicKey>(); Map<int, ECPublicKey> keys = new HashMap<int, ECPublicKey>();
ECPublicKey? identity_key = null; ECPublicKey? identity_key = null;
@ -350,7 +349,7 @@ public class StreamModule : XmppStreamModule {
} catch (Error e) { } catch (Error e) {
if (Plugin.DEBUG) print(@"Unexpected error while publishing bundle: $(e.message)\n"); if (Plugin.DEBUG) print(@"Unexpected error while publishing bundle: $(e.message)\n");
} }
stream.get_module(IDENTITY).active_bundle_requests.remove(jid + @":$(store.local_registration_id)"); stream.get_module(IDENTITY).active_bundle_requests.remove(jid.bare_jid.to_string() + @":$(store.local_registration_id)");
} }
public static void publish_bundles(XmppStream stream, SignedPreKeyRecord signed_pre_key_record, IdentityKeyPair identity_key_pair, Set<PreKeyRecord> pre_key_records, int32 device_id) throws Error { public static void publish_bundles(XmppStream stream, SignedPreKeyRecord signed_pre_key_record, IdentityKeyPair identity_key_pair, Set<PreKeyRecord> pre_key_records, int32 device_id) throws Error {
@ -385,7 +384,7 @@ public class StreamModule : XmppStreamModule {
} }
public class ReceivedPipelineListener : StanzaListener<Message.Stanza> { public class ReceivedPipelineListener : StanzaListener<MessageStanza> {
private const string[] after_actions_const = {"EXTRACT_MESSAGE_2"}; private const string[] after_actions_const = {"EXTRACT_MESSAGE_2"};
@ -398,7 +397,7 @@ public class ReceivedPipelineListener : StanzaListener<Message.Stanza> {
this.store = store; this.store = store;
} }
public override async void run(Core.XmppStream stream, Message.Stanza message) { public override async void run(XmppStream stream, MessageStanza message) {
StanzaNode? _encrypted = message.stanza.get_subnode("encrypted", NS_URI); StanzaNode? _encrypted = message.stanza.get_subnode("encrypted", NS_URI);
if (_encrypted == null || MessageFlag.get_flag(message) != null || message.from == null) return; if (_encrypted == null || MessageFlag.get_flag(message) != null || message.from == null) return;
StanzaNode encrypted = (!)_encrypted; StanzaNode encrypted = (!)_encrypted;
@ -419,7 +418,7 @@ public class ReceivedPipelineListener : StanzaListener<Message.Stanza> {
uint8[] key; uint8[] key;
uint8[] ciphertext = Base64.decode((!)payload); uint8[] ciphertext = Base64.decode((!)payload);
uint8[] iv = Base64.decode((!)iv_node); uint8[] iv = Base64.decode((!)iv_node);
Address address = new Address(get_bare_jid((!)message.from), header.get_attribute_int("sid")); Address address = new Address(message.from.bare_jid.to_string(), header.get_attribute_int("sid"));
if (key_node.get_attribute_bool("prekey")) { if (key_node.get_attribute_bool("prekey")) {
PreKeySignalMessage msg = Plugin.get_context().deserialize_pre_key_signal_message(Base64.decode((!)key_node_content)); PreKeySignalMessage msg = Plugin.get_context().deserialize_pre_key_signal_message(Base64.decode((!)key_node_content));
SessionCipher cipher = store.create_session_cipher(address); SessionCipher cipher = store.create_session_cipher(address);

View file

@ -1,6 +1,7 @@
using Qlite; using Qlite;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Plugins.OpenPgp { namespace Dino.Plugins.OpenPgp {

View file

@ -1,6 +1,7 @@
using Gee; using Gee;
using Dino.Entities; using Dino.Entities;
using Xmpp;
namespace Dino.Plugins.OpenPgp { namespace Dino.Plugins.OpenPgp {

View file

@ -63,17 +63,17 @@ public class Manager : StreamInteractionModule, Object {
return gpgkeys; return gpgkeys;
} }
private void on_pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) { private void on_pre_message_received(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation) {
if (MessageFlag.get_flag(message_stanza) != null && MessageFlag.get_flag(message_stanza).decrypted) { if (MessageFlag.get_flag(message_stanza) != null && MessageFlag.get_flag(message_stanza).decrypted) {
message.encryption = Encryption.PGP; message.encryption = Encryption.PGP;
} }
} }
private void check_encypt(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) { private void check_encypt(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation) {
try { try {
if (message.encryption == Encryption.PGP) { if (message.encryption == Encryption.PGP) {
GPG.Key[] keys = get_key_fprs(conversation); GPG.Key[] keys = get_key_fprs(conversation);
Core.XmppStream? stream = stream_interactor.get_stream(conversation.account); XmppStream? stream = stream_interactor.get_stream(conversation.account);
if (stream != null) { if (stream != null) {
bool encrypted = stream.get_module(Module.IDENTITY).encrypt(message_stanza, keys); bool encrypted = stream.get_module(Module.IDENTITY).encrypt(message_stanza, keys);
if (!encrypted) message.marked = Entities.Message.Marked.WONTSEND; if (!encrypted) message.marked = Entities.Message.Marked.WONTSEND;
@ -91,7 +91,7 @@ public class Manager : StreamInteractionModule, Object {
private void on_account_added(Account account) { private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Module.IDENTITY).received_jid_key_id.connect((stream, jid, key_id) => { stream_interactor.module_manager.get_module(account, Module.IDENTITY).received_jid_key_id.connect((stream, jid, key_id) => {
on_jid_key_received(account, new Jid(jid), key_id); on_jid_key_received(account, jid, key_id);
}); });
} }

View file

@ -37,7 +37,7 @@ public class Plugin : Plugins.RootInterface, Object {
public void shutdown() { } public void shutdown() { }
private void on_initialize_account_modules(Account account, ArrayList<Xmpp.Core.XmppStreamModule> modules) { private void on_initialize_account_modules(Account account, ArrayList<Xmpp.XmppStreamModule> modules) {
Module module = new Module(db.get_account_key(account)); Module module = new Module(db.get_account_key(account));
this.modules[account] = module; this.modules[account] = module;
modules.add(module); modules.add(module);

View file

@ -1,18 +1,18 @@
using Gee; using Gee;
using Xmpp; using Xmpp;
using Xmpp.Core; using Xmpp;
namespace Dino.Plugins.OpenPgp { namespace Dino.Plugins.OpenPgp {
public class Flag : XmppStreamFlag { public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "pgp"); public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "pgp");
public HashMap<string, string> key_ids = new HashMap<string, string>(); public HashMap<Jid, string> key_ids = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
public string? get_key_id(string jid) { return key_ids[get_bare_jid(jid)]; } public string? get_key_id(Jid jid) { return key_ids[jid]; }
public void set_key_id(string jid, string key) { key_ids[get_bare_jid(jid)] = key; } public void set_key_id(Jid jid, string key) { key_ids[jid] = key; }
public override string get_ns() { return NS_URI; } public override string get_ns() { return NS_URI; }

View file

@ -1,7 +1,6 @@
using GPG; using GPG;
using Xmpp; using Xmpp;
using Xmpp.Core;
namespace Dino.Plugins.OpenPgp { namespace Dino.Plugins.OpenPgp {
private const string NS_URI = "jabber:x"; private const string NS_URI = "jabber:x";
@ -9,9 +8,9 @@ namespace Dino.Plugins.OpenPgp {
private const string NS_URI_SIGNED = NS_URI + ":signed"; private const string NS_URI_SIGNED = NS_URI + ":signed";
public class Module : XmppStreamModule { public class Module : XmppStreamModule {
public static Core.ModuleIdentity<Module> IDENTITY = new Core.ModuleIdentity<Module>(NS_URI, "0027_current_pgp_usage"); public static Xmpp.ModuleIdentity<Module> IDENTITY = new Xmpp.ModuleIdentity<Module>(NS_URI, "0027_current_pgp_usage");
public signal void received_jid_key_id(XmppStream stream, string jid, string key_id); public signal void received_jid_key_id(XmppStream stream, Jid jid, string key_id);
private string? signed_status = null; private string? signed_status = null;
private Key? own_key = null; private Key? own_key = null;
@ -33,7 +32,7 @@ namespace Dino.Plugins.OpenPgp {
} }
} }
public bool encrypt(Message.Stanza message, GPG.Key[] keys) { public bool encrypt(MessageStanza message, GPG.Key[] keys) {
string? enc_body = gpg_encrypt(message.body, keys); string? enc_body = gpg_encrypt(message.body, keys);
if (enc_body != null) { if (enc_body != null) {
message.stanza.put_node(new StanzaNode.build("x", NS_URI_ENCRYPTED).add_self_xmlns().put_node(new StanzaNode.text(enc_body))); message.stanza.put_node(new StanzaNode.build("x", NS_URI_ENCRYPTED).add_self_xmlns().put_node(new StanzaNode.text(enc_body)));
@ -46,14 +45,14 @@ namespace Dino.Plugins.OpenPgp {
public override void attach(XmppStream stream) { public override void attach(XmppStream stream) {
stream.get_module(Presence.Module.IDENTITY).received_presence.connect(on_received_presence); stream.get_module(Presence.Module.IDENTITY).received_presence.connect(on_received_presence);
stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.connect(on_pre_send_presence_stanza); stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.connect(on_pre_send_presence_stanza);
stream.get_module(Message.Module.IDENTITY).received_pipeline.connect(received_pipeline_decrypt_listener); stream.get_module(MessageModule.IDENTITY).received_pipeline.connect(received_pipeline_decrypt_listener);
stream.add_flag(new Flag()); stream.add_flag(new Flag());
} }
public override void detach(XmppStream stream) { public override void detach(XmppStream stream) {
stream.get_module(Presence.Module.IDENTITY).received_presence.disconnect(on_received_presence); stream.get_module(Presence.Module.IDENTITY).received_presence.disconnect(on_received_presence);
stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.disconnect(on_pre_send_presence_stanza); stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.disconnect(on_pre_send_presence_stanza);
stream.get_module(Message.Module.IDENTITY).received_pipeline.disconnect(received_pipeline_decrypt_listener); stream.get_module(MessageModule.IDENTITY).received_pipeline.disconnect(received_pipeline_decrypt_listener);
} }
public static void require(XmppStream stream) { public static void require(XmppStream stream) {
@ -121,12 +120,12 @@ namespace Dino.Plugins.OpenPgp {
} }
} }
public class MessageFlag : Message.MessageFlag { public class MessageFlag : Xmpp.MessageFlag {
public const string id = "pgp"; public const string id = "pgp";
public bool decrypted = false; public bool decrypted = false;
public static MessageFlag? get_flag(Message.Stanza message) { public static MessageFlag? get_flag(MessageStanza message) {
return (MessageFlag) message.get_flag(NS_URI, id); return (MessageFlag) message.get_flag(NS_URI, id);
} }
@ -134,14 +133,14 @@ namespace Dino.Plugins.OpenPgp {
public override string get_id() { return id; } public override string get_id() { return id; }
} }
public class ReceivedPipelineDecryptListener : StanzaListener<Message.Stanza> { public class ReceivedPipelineDecryptListener : StanzaListener<MessageStanza> {
private const string[] after_actions_const = {"MODIFY_BODY"}; private const string[] after_actions_const = {"MODIFY_BODY"};
public override string action_group { get { return "ENCRYPT_BODY"; } } public override string action_group { get { return "ENCRYPT_BODY"; } }
public override string[] after_actions { get { return after_actions_const; } } public override string[] after_actions { get { return after_actions_const; } }
public override async void run(Core.XmppStream stream, Message.Stanza message) { public override async void run(XmppStream stream, MessageStanza message) {
string? encrypted = get_cyphertext(message); string? encrypted = get_cyphertext(message);
if (encrypted != null) { if (encrypted != null) {
MessageFlag flag = new MessageFlag(); MessageFlag flag = new MessageFlag();
@ -171,7 +170,7 @@ public class ReceivedPipelineDecryptListener : StanzaListener<Message.Stanza> {
return res; return res;
} }
private string? get_cyphertext(Message.Stanza message) { private string? get_cyphertext(MessageStanza message) {
StanzaNode? x_node = message.stanza.get_subnode("x", NS_URI_ENCRYPTED); StanzaNode? x_node = message.stanza.get_subnode("x", NS_URI_ENCRYPTED);
return x_node == null ? null : x_node.get_string_content(); return x_node == null ? null : x_node.get_string_content();
} }

View file

@ -21,6 +21,7 @@ SOURCES
"src/module/bind.vala" "src/module/bind.vala"
"src/module/iq/module.vala" "src/module/iq/module.vala"
"src/module/iq/stanza.vala" "src/module/iq/stanza.vala"
"src/module/jid.vala"
"src/module/message/module.vala" "src/module/message/module.vala"
"src/module/message/stanza.vala" "src/module/message/stanza.vala"
"src/module/presence/flag.vala" "src/module/presence/flag.vala"

View file

@ -1,6 +1,6 @@
using Gee; using Gee;
namespace Xmpp.Core { namespace Xmpp {
public class NamespaceState { public class NamespaceState {
private HashMap<string, string> uri_to_name = new HashMap<string, string> (); private HashMap<string, string> uri_to_name = new HashMap<string, string> ();

View file

@ -1,4 +1,4 @@
namespace Xmpp.Core { namespace Xmpp {
public class StanzaAttribute : StanzaEntry { public class StanzaAttribute : StanzaEntry {

View file

@ -1,6 +1,6 @@
using Gee; using Gee;
namespace Xmpp.Core { namespace Xmpp {
public abstract class StanzaEntry { public abstract class StanzaEntry {
protected const string ANSI_COLOR_END = "\x1b[0m"; protected const string ANSI_COLOR_END = "\x1b[0m";

View file

@ -1,6 +1,6 @@
using Gee; using Gee;
namespace Xmpp.Core { namespace Xmpp {
public const string XMLNS_URI = "http://www.w3.org/2000/xmlns/"; public const string XMLNS_URI = "http://www.w3.org/2000/xmlns/";
public const string XML_URI = "http://www.w3.org/XML/1998/namespace"; public const string XML_URI = "http://www.w3.org/XML/1998/namespace";

View file

@ -1,4 +1,5 @@
namespace Xmpp.Core { namespace Xmpp {
public class StanzaWriter { public class StanzaWriter {
private OutputStream output; private OutputStream output;

View file

@ -1,6 +1,6 @@
using Gee; using Gee;
namespace Xmpp.Core { namespace Xmpp {
public class XmppLog { public class XmppLog {
protected const string ANSI_COLOR_END = "\x1b[0m"; protected const string ANSI_COLOR_END = "\x1b[0m";

View file

@ -1,6 +1,6 @@
using Gee; using Gee;
namespace Xmpp.Core { namespace Xmpp {
public errordomain IOStreamError { public errordomain IOStreamError {
READ, READ,
@ -13,7 +13,7 @@ public errordomain IOStreamError {
public class XmppStream { public class XmppStream {
public const string NS_URI = "http://etherx.jabber.org/streams"; public const string NS_URI = "http://etherx.jabber.org/streams";
public string remote_name; public Jid remote_name;
public XmppLog log = new XmppLog(); public XmppLog log = new XmppLog();
public StanzaNode? features { get; private set; default = new StanzaNode.build("features", NS_URI); } public StanzaNode? features { get; private set; default = new StanzaNode.build("features", NS_URI); }
@ -43,13 +43,13 @@ public class XmppStream {
} }
public async void connect(string? remote_name = null) throws IOStreamError { public async void connect(string? remote_name = null) throws IOStreamError {
if (remote_name != null) this.remote_name = (!)remote_name; if (remote_name != null) this.remote_name = Jid.parse(remote_name);
attach_negotation_modules(); attach_negotation_modules();
try { try {
int min_priority = -1; int min_priority = -1;
ConnectionProvider? best_provider = null; ConnectionProvider? best_provider = null;
foreach (ConnectionProvider connection_provider in connection_providers) { foreach (ConnectionProvider connection_provider in connection_providers) {
int? priority = yield connection_provider.get_priority(remote_name); int? priority = yield connection_provider.get_priority(this.remote_name);
if (priority != null && (priority < min_priority || min_priority == -1)) { if (priority != null && (priority < min_priority || min_priority == -1)) {
min_priority = priority; min_priority = priority;
best_provider = connection_provider; best_provider = connection_provider;
@ -60,7 +60,7 @@ public class XmppStream {
stream = yield best_provider.connect(this); stream = yield best_provider.connect(this);
} }
if (stream == null) { if (stream == null) {
stream = yield (new SocketClient()).connect_async(new NetworkService("xmpp-client", "tcp", this.remote_name)); stream = yield (new SocketClient()).connect_async(new NetworkService("xmpp-client", "tcp", this.remote_name.to_string()));
} }
if (stream == null) { if (stream == null) {
throw new IOStreamError.CONNECT("client.connect() returned null"); throw new IOStreamError.CONNECT("client.connect() returned null");
@ -187,7 +187,7 @@ public class XmppStream {
private async void setup() throws IOStreamError { private async void setup() throws IOStreamError {
StanzaNode outs = new StanzaNode.build("stream", "http://etherx.jabber.org/streams") StanzaNode outs = new StanzaNode.build("stream", "http://etherx.jabber.org/streams")
.put_attribute("to", remote_name) .put_attribute("to", remote_name.to_string())
.put_attribute("version", "1.0") .put_attribute("version", "1.0")
.put_attribute("xmlns", "jabber:client") .put_attribute("xmlns", "jabber:client")
.put_attribute("stream", "http://etherx.jabber.org/streams", XMLNS_URI); .put_attribute("stream", "http://etherx.jabber.org/streams", XMLNS_URI);
@ -349,7 +349,7 @@ public abstract class XmppStreamNegotiationModule : XmppStreamModule {
} }
public abstract class ConnectionProvider { public abstract class ConnectionProvider {
public async abstract int? get_priority(string remote_name); public async abstract int? get_priority(Jid remote_name);
public async abstract IOStream? connect(XmppStream stream); public async abstract IOStream? connect(XmppStream stream);
public abstract string get_id(); public abstract string get_id();
} }
@ -357,11 +357,11 @@ public abstract class ConnectionProvider {
public class StartTlsConnectionProvider : ConnectionProvider { public class StartTlsConnectionProvider : ConnectionProvider {
private SrvTarget? srv_target; private SrvTarget? srv_target;
public async override int? get_priority(string remote_name) { public async override int? get_priority(Jid remote_name) {
GLib.List<SrvTarget>? xmpp_target = null; GLib.List<SrvTarget>? xmpp_target = null;
try { try {
GLibFixes.Resolver resolver = GLibFixes.Resolver.get_default(); GLibFixes.Resolver resolver = GLibFixes.Resolver.get_default();
xmpp_target = yield resolver.lookup_service_async("xmpp-client", "tcp", remote_name, null); xmpp_target = yield resolver.lookup_service_async("xmpp-client", "tcp", remote_name.to_string(), null);
} catch (Error e) { } catch (Error e) {
return null; return null;
} }

View file

@ -1,5 +1,3 @@
using Xmpp.Core;
namespace Xmpp.Bind { namespace Xmpp.Bind {
private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-bind"; private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-bind";
@ -9,7 +7,7 @@ namespace Xmpp.Bind {
public string requested_resource { get; set; } public string requested_resource { get; set; }
public signal void bound_to_resource(XmppStream stream, string my_jid); public signal void bound_to_resource(XmppStream stream, Jid my_jid);
public Module(string requested_resource) { public Module(string requested_resource) {
this.requested_resource = requested_resource; this.requested_resource = requested_resource;
@ -20,7 +18,7 @@ namespace Xmpp.Bind {
if (flag == null || flag.finished) return; if (flag == null || flag.finished) return;
if (iq.type_ == Iq.Stanza.TYPE_RESULT) { if (iq.type_ == Iq.Stanza.TYPE_RESULT) {
flag.my_jid = iq.stanza.get_subnode("jid", NS_URI, true).get_string_content(); flag.my_jid = Jid.parse(iq.stanza.get_subnode("jid", NS_URI, true).get_string_content());
flag.finished = true; flag.finished = true;
bound_to_resource(stream, flag.my_jid); bound_to_resource(stream, flag.my_jid);
} }
@ -62,7 +60,7 @@ namespace Xmpp.Bind {
public class Flag : XmppStreamFlag { public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "bind"); public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "bind");
public string? my_jid; public Jid? my_jid;
public bool finished = false; public bool finished = false;
public override string get_ns() { return NS_URI; } public override string get_ns() { return NS_URI; }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Iq { namespace Xmpp.Iq {
private const string NS_URI = "jabber:client"; private const string NS_URI = "jabber:client";

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Iq { namespace Xmpp.Iq {
public class Stanza : Xmpp.Stanza { public class Stanza : Xmpp.Stanza {
@ -44,7 +42,7 @@ public class Stanza : Xmpp.Stanza {
stanza.put_node(associated_child); stanza.put_node(associated_child);
} }
} }
public Stanza.from_stanza(StanzaNode stanza_node, string? my_jid) { public Stanza.from_stanza(StanzaNode stanza_node, Jid? my_jid) {
base.incoming(stanza_node, my_jid); base.incoming(stanza_node, my_jid);
} }
} }

View file

@ -1,28 +1,36 @@
public class Dino.Entities.Jid : Object { namespace Xmpp {
public string? localpart { get; set; }
public string domainpart { get; set; } public class Jid {
public string? resourcepart { get; set; } public string? localpart;
public string domainpart;
public string? resourcepart;
public Jid bare_jid { public Jid bare_jid {
owned get { return localpart != null ? new Jid(@"$localpart@$domainpart") : new Jid(domainpart); } owned get { return is_bare() ? this : new Jid.components(localpart, domainpart, null); }
} }
private string jid { get; private set; } public Jid domain_jid {
owned get { return is_domain() ? this : new Jid.components(null, domainpart, null); }
}
private string jid;
public Jid(string jid) { public Jid(string jid) {
Jid? parsed = Jid.parse(jid); Jid? parsed = Jid.parse(jid);
string? localpart = parsed != null ? parsed.localpart : null; string? localpart = parsed != null ? (owned) parsed.localpart : null;
string domainpart = parsed != null ? parsed.domainpart : jid; string domainpart = parsed != null ? (owned) parsed.domainpart : jid;
string? resourcepart = parsed != null ? parsed.resourcepart : null; string? resourcepart = parsed != null ? (owned) parsed.resourcepart : null;
this.components(localpart, domainpart, resourcepart); this.intern(jid, (owned) localpart, (owned) domainpart, (owned) resourcepart);
} }
public Jid.with_resource(string bare_jid, string resource) { private Jid.intern(owned string jid, owned string? localpart, owned string domainpart, owned string? resourcepart) {
Jid? parsed = Jid.parse(bare_jid); this.jid = (owned) jid;
this.components(parsed.localpart, parsed.domainpart, resource); this.localpart = (owned) localpart;
this.domainpart = (owned) domainpart;
this.resourcepart = (owned) resourcepart;
} }
public Jid.components(string? localpart, string domainpart, string? resourcepart) { public Jid.components(owned string? localpart, owned string domainpart, owned string? resourcepart) {
string jid = domainpart; string jid = domainpart;
if (localpart != null) { if (localpart != null) {
jid = @"$localpart@$jid"; jid = @"$localpart@$jid";
@ -31,9 +39,9 @@ public class Dino.Entities.Jid : Object {
jid = @"$jid/$resourcepart"; jid = @"$jid/$resourcepart";
} }
this.jid = jid; this.jid = jid;
this.localpart = localpart; this.localpart = (owned) localpart;
this.domainpart = domainpart; this.domainpart = (owned) domainpart;
this.resourcepart = resourcepart; this.resourcepart = (owned) resourcepart;
} }
public static Jid? parse(string jid) { public static Jid? parse(string jid) {
@ -48,9 +56,17 @@ public class Dino.Entities.Jid : Object {
if (slash_index != -1 && resourcepart == "") return null; if (slash_index != -1 && resourcepart == "") return null;
if (at_index != -1 && localpart == "") return null; if (at_index != -1 && localpart == "") return null;
return new Jid.intern(jid, (owned) localpart, (owned) domainpart, (owned) resourcepart);
}
public Jid with_resource(string? resourcepart) {
return new Jid.components(localpart, domainpart, resourcepart); return new Jid.components(localpart, domainpart, resourcepart);
} }
public bool is_domain() {
return localpart == null && resourcepart == null;
}
public bool is_bare() { public bool is_bare() {
return localpart != null && resourcepart == null; return localpart != null && resourcepart == null;
} }
@ -87,3 +103,5 @@ public class Dino.Entities.Jid : Object {
return jid.to_string().hash(); return jid.to_string().hash();
} }
} }
}

View file

@ -1,27 +1,27 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Message {
namespace Xmpp {
private const string NS_URI = "jabber:client"; private const string NS_URI = "jabber:client";
public class Module : XmppStreamModule { public class MessageModule : XmppStreamModule {
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "message_module"); public static ModuleIdentity<MessageModule> IDENTITY = new ModuleIdentity<MessageModule>(NS_URI, "message_module");
public StanzaListenerHolder<Message.Stanza> received_pipeline = new StanzaListenerHolder<Message.Stanza>(); public StanzaListenerHolder<MessageStanza> received_pipeline = new StanzaListenerHolder<MessageStanza>();
public StanzaListenerHolder<Message.Stanza> send_pipeline = new StanzaListenerHolder<Message.Stanza>(); public StanzaListenerHolder<MessageStanza> send_pipeline = new StanzaListenerHolder<MessageStanza>();
public signal void pre_received_message(XmppStream stream, Message.Stanza message); public signal void pre_received_message(XmppStream stream, MessageStanza message);
public signal void received_message(XmppStream stream, Message.Stanza message); public signal void received_message(XmppStream stream, MessageStanza message);
public void send_message(XmppStream stream, Message.Stanza message) { public void send_message(XmppStream stream, MessageStanza message) {
send_pipeline.run.begin(stream, message, (obj, res) => { send_pipeline.run.begin(stream, message, (obj, res) => {
stream.write(message.stanza); stream.write(message.stanza);
}); });
} }
public async void received_message_stanza_async(XmppStream stream, StanzaNode node) { public async void received_message_stanza_async(XmppStream stream, StanzaNode node) {
Message.Stanza message = new Message.Stanza.from_stanza(node, stream.get_flag(Bind.Flag.IDENTITY).my_jid); MessageStanza message = new MessageStanza.from_stanza(node, stream.get_flag(Bind.Flag.IDENTITY).my_jid);
yield received_pipeline.run(stream, message); yield received_pipeline.run(stream, message);
received_message(stream, message); received_message(stream, message);
} }

View file

@ -1,10 +1,8 @@
using Gee; using Gee;
using Xmpp.Core; namespace Xmpp {
namespace Xmpp.Message { public class MessageStanza : Xmpp.Stanza {
public class Stanza : Xmpp.Stanza {
public const string NODE_BODY = "body"; public const string NODE_BODY = "body";
public const string NODE_SUBJECT = "subject"; public const string NODE_SUBJECT = "subject";
public const string NODE_THREAD = "thread"; public const string NODE_THREAD = "thread";
@ -40,12 +38,12 @@ public class Stanza : Xmpp.Stanza {
set { base.type_ = value; } set { base.type_ = value; }
} }
public Stanza(string? id = null) { public MessageStanza(string? id = null) {
base.outgoing(new StanzaNode.build("message")); base.outgoing(new StanzaNode.build("message"));
stanza.set_attribute(ATTRIBUTE_ID, id ?? random_uuid()); stanza.set_attribute(ATTRIBUTE_ID, id ?? random_uuid());
} }
public Stanza.from_stanza(StanzaNode stanza_node, string my_jid) { public MessageStanza.from_stanza(StanzaNode stanza_node, Jid my_jid) {
base.incoming(stanza_node, my_jid); base.incoming(stanza_node, my_jid);
} }

View file

@ -1,60 +1,60 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Presence { namespace Xmpp.Presence {
public class Flag : XmppStreamFlag { public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "presence"); public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "presence");
private HashMap<string, ConcurrentList<string>> resources = new HashMap<string, ConcurrentList<string>>(); private HashMap<Jid, Gee.List<Jid>> resources = new HashMap<Jid, Gee.List<Jid>>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, Presence.Stanza> presences = new HashMap<string, Presence.Stanza>(); private HashMap<Jid, Presence.Stanza> presences = new HashMap<Jid, Presence.Stanza>(Jid.hash_func, Jid.equals_func);
public Set<string> get_available_jids() { public Set<Jid> get_available_jids() {
return resources.keys; return resources.keys;
} }
public Gee.List<string>? get_resources(string bare_jid) { public Gee.List<Jid>? get_resources(Jid jid) {
return resources[bare_jid]; return resources[jid];
} }
public Presence.Stanza? get_presence(string full_jid) { public Presence.Stanza? get_presence(Jid full_jid) {
return presences[full_jid]; return presences[full_jid];
} }
public void add_presence(Presence.Stanza presence) { public void add_presence(Presence.Stanza presence) {
string bare_jid = get_bare_jid(presence.from); if (!resources.has_key(presence.from)) {
if (!resources.has_key(bare_jid)) { resources[presence.from] = new ArrayList<Jid>(Jid.equals_func);
resources[bare_jid] = new ConcurrentList<string>();
} }
if (resources[bare_jid].contains(presence.from)) { if (resources[presence.from].contains(presence.from)) {
resources[bare_jid].remove(presence.from); resources[presence.from].remove(presence.from);
} }
resources[bare_jid].add(presence.from); resources[presence.from].add(presence.from);
presences[presence.from] = presence; presences[presence.from] = presence;
} }
public void remove_presence(string jid) { public void remove_presence(Jid jid) {
string bare_jid = get_bare_jid(jid); if (resources.has_key(jid)) {
if (resources.has_key(bare_jid)) { if (jid.is_bare()) {
if (is_bare_jid(jid)) { foreach (Jid full_jid in resources[jid]) {
foreach (string full_jid in resources[jid]) {
presences.unset(full_jid); presences.unset(full_jid);
} }
resources.unset(jid); resources.unset(jid);
} else { } else {
resources[bare_jid].remove(jid); resources[jid].remove(jid);
if (resources[bare_jid].size == 0) { if (resources[jid].size == 0) {
resources.unset(bare_jid); resources.unset(jid);
} }
presences.unset(jid); presences.unset(jid);
} }
} }
} }
public override string get_ns() { return NS_URI; } public override string get_ns() {
return NS_URI;
}
public override string get_id() { return IDENTITY.id; } public override string get_id() {
return IDENTITY.id;
}
} }
} }

View file

@ -1,5 +1,3 @@
using Xmpp.Core;
namespace Xmpp.Presence { namespace Xmpp.Presence {
private const string NS_URI = "jabber:client"; private const string NS_URI = "jabber:client";
@ -10,39 +8,39 @@ namespace Xmpp.Presence {
public signal void pre_send_presence_stanza(XmppStream stream, Presence.Stanza presence); public signal void pre_send_presence_stanza(XmppStream stream, Presence.Stanza presence);
public signal void initial_presence_sent(XmppStream stream, Presence.Stanza presence); public signal void initial_presence_sent(XmppStream stream, Presence.Stanza presence);
public signal void received_available(XmppStream stream, Presence.Stanza presence); public signal void received_available(XmppStream stream, Presence.Stanza presence);
public signal void received_available_show(XmppStream stream, string jid, string show); public signal void received_available_show(XmppStream stream, Jid jid, string show);
public signal void received_unavailable(XmppStream stream, Presence.Stanza presence); public signal void received_unavailable(XmppStream stream, Presence.Stanza presence);
public signal void received_subscription_request(XmppStream stream, string jid); public signal void received_subscription_request(XmppStream stream, Jid jid);
public signal void received_unsubscription(XmppStream stream, string jid); public signal void received_unsubscription(XmppStream stream, Jid jid);
public bool available_resource = true; public bool available_resource = true;
public void request_subscription(XmppStream stream, string bare_jid) { public void request_subscription(XmppStream stream, Jid bare_jid) {
Presence.Stanza presence = new Presence.Stanza(); Presence.Stanza presence = new Presence.Stanza();
presence.to = bare_jid; presence.to = bare_jid;
presence.type_ = Presence.Stanza.TYPE_SUBSCRIBE; presence.type_ = Presence.Stanza.TYPE_SUBSCRIBE;
send_presence(stream, presence); send_presence(stream, presence);
} }
public void approve_subscription(XmppStream stream, string bare_jid) { public void approve_subscription(XmppStream stream, Jid bare_jid) {
Presence.Stanza presence = new Presence.Stanza(); Presence.Stanza presence = new Presence.Stanza();
presence.to = bare_jid; presence.to = bare_jid;
presence.type_ = Presence.Stanza.TYPE_SUBSCRIBED; presence.type_ = Presence.Stanza.TYPE_SUBSCRIBED;
send_presence(stream, presence); send_presence(stream, presence);
} }
public void deny_subscription(XmppStream stream, string bare_jid) { public void deny_subscription(XmppStream stream, Jid bare_jid) {
cancel_subscription(stream, bare_jid); cancel_subscription(stream, bare_jid);
} }
public void cancel_subscription(XmppStream stream, string bare_jid) { public void cancel_subscription(XmppStream stream, Jid bare_jid) {
Presence.Stanza presence = new Presence.Stanza(); Presence.Stanza presence = new Presence.Stanza();
presence.to = bare_jid; presence.to = bare_jid;
presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBED; presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBED;
send_presence(stream, presence); send_presence(stream, presence);
} }
public void unsubscribe(XmppStream stream, string bare_jid) { public void unsubscribe(XmppStream stream, Jid bare_jid) {
Presence.Stanza presence = new Presence.Stanza(); Presence.Stanza presence = new Presence.Stanza();
presence.to = bare_jid; presence.to = bare_jid;
presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBE; presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBE;

View file

@ -1,5 +1,3 @@
using Xmpp.Core;
namespace Xmpp.Presence { namespace Xmpp.Presence {
public class Stanza : Xmpp.Stanza { public class Stanza : Xmpp.Stanza {
@ -85,9 +83,9 @@ public class Stanza : Xmpp.Stanza {
this.id = id ?? random_uuid(); this.id = id ?? random_uuid();
} }
public Stanza.from_stanza(StanzaNode stanza_node, string my_jid) { public Stanza.from_stanza(StanzaNode stanza_node, Jid my_jid) {
base.incoming(stanza_node, my_jid); base.incoming(stanza_node, my_jid);
} }
} }
} }

View file

@ -1,14 +1,12 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Roster { namespace Xmpp.Roster {
public class Flag : XmppStreamFlag { public class Flag : XmppStreamFlag {
public const string ID = "roster"; public const string ID = "roster";
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, ID); public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, ID);
public HashMap<string, Item> roster_items = new HashMap<string, Item>(); public HashMap<Jid, Item> roster_items = new HashMap<Jid, Item>();
public string? iq_id; public string? iq_id;
@ -16,7 +14,7 @@ public class Flag : XmppStreamFlag {
return roster_items.values; return roster_items.values;
} }
public Item? get_item(string jid) { public Item? get_item(Jid jid) {
return roster_items[jid]; return roster_items[jid];
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Roster { namespace Xmpp.Roster {
public class Item { public class Item {
@ -18,9 +16,10 @@ public class Item {
public StanzaNode stanza_node; public StanzaNode stanza_node;
public string jid { private Jid jid_;
get { return stanza_node.get_attribute(NODE_JID); } public Jid jid {
set { stanza_node.set_attribute(NODE_JID, value); } get { return jid_ ?? (jid_ = Jid.parse(stanza_node.get_attribute(NODE_JID))); }
set { stanza_node.set_attribute(NODE_JID, value.to_string()); }
} }
public string? name { public string? name {
@ -42,4 +41,4 @@ public class Item {
} }
} }
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Roster { namespace Xmpp.Roster {
private const string NS_URI = "jabber:iq:roster"; private const string NS_URI = "jabber:iq:roster";
@ -16,7 +14,7 @@ public class Module : XmppStreamModule, Iq.Handler {
public bool interested_resource = true; public bool interested_resource = true;
public void add_jid(XmppStream stream, string jid, string? handle = null) { public void add_jid(XmppStream stream, Jid jid, string? handle = null) {
Item roster_item = new Item(); Item roster_item = new Item();
roster_item.jid = jid; roster_item.jid = jid;
if (handle != null) { if (handle != null) {
@ -25,7 +23,7 @@ public class Module : XmppStreamModule, Iq.Handler {
roster_set(stream, roster_item); roster_set(stream, roster_item);
} }
public void remove_jid(XmppStream stream, string jid) { public void remove_jid(XmppStream stream, Jid jid) {
Item roster_item = new Item(); Item roster_item = new Item();
roster_item.jid = jid; roster_item.jid = jid;
roster_item.subscription = Item.SUBSCRIPTION_REMOVE; roster_item.subscription = Item.SUBSCRIPTION_REMOVE;
@ -37,7 +35,7 @@ public class Module : XmppStreamModule, Iq.Handler {
* Set a handle for a jid * Set a handle for a jid
* @param handle Handle to be set. If null, any handle will be removed. * @param handle Handle to be set. If null, any handle will be removed.
*/ */
public void set_jid_handle(XmppStream stream, string jid, string? handle) { public void set_jid_handle(XmppStream stream, Jid jid, string? handle) {
Flag flag = stream.get_flag(Flag.IDENTITY); Flag flag = stream.get_flag(Flag.IDENTITY);
Item item = flag.get_item(jid) ?? new Item() { jid=jid }; Item item = flag.get_item(jid) ?? new Item() { jid=jid };
item.name = handle != null ? handle : ""; item.name = handle != null ? handle : "";

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Roster { namespace Xmpp.Roster {
public class VersioningModule : XmppStreamModule { public class VersioningModule : XmppStreamModule {

View file

@ -1,5 +1,3 @@
using Xmpp.Core;
namespace Xmpp.PlainSasl { namespace Xmpp.PlainSasl {
private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-sasl"; private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-sasl";
@ -56,16 +54,16 @@ namespace Xmpp.PlainSasl {
} }
} }
if (!supportsPlain) { if (!supportsPlain) {
stderr.printf("Server at %s does not support %s auth, use full-features Sasl implementation!\n", stream.remote_name, MECHANISM); stderr.printf("Server at %s does not support %s auth, use full-features Sasl implementation!\n", stream.remote_name.to_string(), MECHANISM);
return; return;
} }
if (!name.contains("@")) { if (!name.contains("@")) {
name = "%s@%s".printf(name, stream.remote_name); name = "%s@%s".printf(name, stream.remote_name.to_string());
} }
if (!use_full_name && name.contains("@")) { if (!use_full_name && name.contains("@")) {
var split = name.split("@"); var split = name.split("@");
if (split[1] == stream.remote_name) { if (split[1] == stream.remote_name.to_string()) {
name = split[0]; name = split[0];
} else { } else {
use_full_name = true; use_full_name = true;
@ -74,7 +72,7 @@ namespace Xmpp.PlainSasl {
var name = this.name; var name = this.name;
if (!use_full_name && name.contains("@")) { if (!use_full_name && name.contains("@")) {
var split = name.split("@"); var split = name.split("@");
if (split[1] == stream.remote_name) { if (split[1] == stream.remote_name.to_string()) {
name = split[0]; name = split[0];
} }
} }

View file

@ -1,5 +1,3 @@
using Xmpp.Core;
/* Legacy. RFC 3921 3*/ /* Legacy. RFC 3921 3*/
namespace Xmpp.Session { namespace Xmpp.Session {
private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-session"; private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-session";
@ -24,7 +22,7 @@ public class Module : XmppStreamNegotiationModule {
public override string get_ns() { return NS_URI; } public override string get_ns() { return NS_URI; }
public override string get_id() { return IDENTITY.id; } public override string get_id() { return IDENTITY.id; }
private void on_bound_resource(XmppStream stream, string my_jid) { private void on_bound_resource(XmppStream stream, Jid my_jid) {
StanzaNode? session_node = stream.features.get_subnode("session", NS_URI); StanzaNode? session_node = stream.features.get_subnode("session", NS_URI);
if (session_node != null && session_node.get_subnode("optional", NS_URI) == null) { if (session_node != null && session_node.get_subnode("optional", NS_URI) == null) {
stream.add_flag(new Flag()); stream.add_flag(new Flag());

View file

@ -1,70 +1,70 @@
using Xmpp.Core;
namespace Xmpp { namespace Xmpp {
public class Stanza : Object { public class Stanza : Object {
public const string ATTRIBUTE_FROM = "from"; public const string ATTRIBUTE_FROM = "from";
public const string ATTRIBUTE_ID = "id"; public const string ATTRIBUTE_ID = "id";
public const string ATTRIBUTE_TO = "to"; public const string ATTRIBUTE_TO = "to";
public const string ATTRIBUTE_TYPE = "type"; public const string ATTRIBUTE_TYPE = "type";
public const string TYPE_ERROR = "error"; public const string TYPE_ERROR = "error";
private string? my_jid; private Jid? my_jid;
private Jid? from_;
private Jid? to_;
public virtual string? from { public virtual Jid? from {
owned get { owned get {
string? from_attribute = stanza.get_attribute(ATTRIBUTE_FROM); string? from_attribute = stanza.get_attribute(ATTRIBUTE_FROM);
// "when a client receives a stanza that does not include a 'from' attribute, it MUST assume that the stanza // "when a client receives a stanza that does not include a 'from' attribute, it MUST assume that the stanza
// is from the user's account on the server." (RFC6120 8.1.2.1) // is from the user's account on the server." (RFC6120 8.1.2.1)
if (from_attribute != null) return from_attribute; if (from_attribute != null) return from_ = Jid.parse(from_attribute);
if (my_jid != null) { if (my_jid != null) {
string my_bare_jid = get_bare_jid(my_jid); // has to be left-side value return my_jid.bare_jid;
return my_bare_jid;
}
return null;
} }
set { stanza.set_attribute(ATTRIBUTE_FROM, value); } return null;
}
public virtual string? id {
get { return stanza.get_attribute(ATTRIBUTE_ID); }
set { stanza.set_attribute(ATTRIBUTE_ID, value); }
}
public virtual string? to {
owned get {
string? to_attribute = stanza.get_attribute(ATTRIBUTE_TO);
// "if the stanza does not include a 'to' address then the client MUST treat it as if the 'to' address were
// included with a value of the client's full JID." (RFC6120 8.1.1.1)
return to_attribute == null ? my_jid : to_attribute;
}
set { stanza.set_attribute(ATTRIBUTE_TO, value); }
}
public virtual string? type_ {
get { return stanza.get_attribute(ATTRIBUTE_TYPE); }
set { stanza.set_attribute(ATTRIBUTE_TYPE, value); }
}
public StanzaNode stanza;
public Stanza.incoming(StanzaNode stanza, string? my_jid) {
this.stanza = stanza;
this.my_jid = my_jid;
}
public Stanza.outgoing(StanzaNode stanza) {
this.stanza = stanza;
}
public bool is_error() {
return type_ == TYPE_ERROR;
}
public ErrorStanza? get_error() {
return new ErrorStanza.from_stanza(this.stanza);
} }
set { stanza.set_attribute(ATTRIBUTE_FROM, value.to_string()); }
} }
public virtual string? id {
get { return stanza.get_attribute(ATTRIBUTE_ID); }
set { stanza.set_attribute(ATTRIBUTE_ID, value); }
}
public virtual Jid? to {
owned get {
string? to_attribute = stanza.get_attribute(ATTRIBUTE_TO);
// "if the stanza does not include a 'to' address then the client MUST treat it as if the 'to' address were
// included with a value of the client's full JID." (RFC6120 8.1.1.1)
return to_attribute == null ? my_jid : to_ = Jid.parse(to_attribute);
}
set { stanza.set_attribute(ATTRIBUTE_TO, value.to_string()); }
}
public virtual string? type_ {
get { return stanza.get_attribute(ATTRIBUTE_TYPE); }
set { stanza.set_attribute(ATTRIBUTE_TYPE, value); }
}
public StanzaNode stanza;
public Stanza.incoming(StanzaNode stanza, Jid? my_jid) {
this.stanza = stanza;
this.my_jid = my_jid;
}
public Stanza.outgoing(StanzaNode stanza) {
this.stanza = stanza;
}
public bool is_error() {
return type_ == TYPE_ERROR;
}
public ErrorStanza? get_error() {
return new ErrorStanza.from_stanza(this.stanza);
}
}
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp { namespace Xmpp {
public class ErrorStanza { public class ErrorStanza {
@ -66,4 +64,4 @@ namespace Xmpp {
error_node = stanza.get_subnode("error"); error_node = stanza.get_subnode("error");
} }
} }
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.StreamError { namespace Xmpp.StreamError {
private const string NS_URI = "jabber:client"; private const string NS_URI = "jabber:client";
private const string NS_ERROR = "urn:ietf:params:xml:ns:xmpp-streams"; private const string NS_ERROR = "urn:ietf:params:xml:ns:xmpp-streams";

View file

@ -1,5 +1,3 @@
using Xmpp.Core;
namespace Xmpp.Tls { namespace Xmpp.Tls {
private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-tls"; private const string NS_URI = "urn:ietf:params:xml:ns:xmpp-tls";
@ -52,7 +50,7 @@ namespace Xmpp.Tls {
stream.write(new StanzaNode.build("starttls", NS_URI).add_self_xmlns()); stream.write(new StanzaNode.build("starttls", NS_URI).add_self_xmlns());
} }
if (identity == null) { if (identity == null) {
identity = new NetworkService("xmpp-client", "tcp", stream.remote_name); identity = new NetworkService("xmpp-client", "tcp", stream.remote_name.to_string());
} }
stream.add_flag(new Flag()); stream.add_flag(new Flag());
} }

View file

@ -1,32 +1,22 @@
using Gee; using Gee;
namespace Xmpp { namespace Xmpp {
public string get_bare_jid(string jid) {
return jid.split("/")[0];
}
public bool is_bare_jid(string jid) { public string random_uuid() {
return !jid.contains("/"); uint32 b1 = Random.next_int();
} uint16 b2 = (uint16)Random.next_int();
uint16 b3 = (uint16)(Random.next_int() | 0x4000u) & ~0xb000u;
public string? get_resource_part(string jid) { uint16 b4 = (uint16)(Random.next_int() | 0x8000u) & ~0x4000u;
return jid.split("/")[1]; uint16 b5_1 = (uint16)Random.next_int();
} uint32 b5_2 = Random.next_int();
return "%08x-%04x-%04x-%04x-%04x%08x".printf(b1, b2, b3, b4, b5_1, b5_2);
public string random_uuid() { }
uint32 b1 = Random.next_int();
uint16 b2 = (uint16)Random.next_int();
uint16 b3 = (uint16)(Random.next_int() | 0x4000u) & ~0xb000u;
uint16 b4 = (uint16)(Random.next_int() | 0x8000u) & ~0x4000u;
uint16 b5_1 = (uint16)Random.next_int();
uint32 b5_2 = Random.next_int();
return "%08x-%04x-%04x-%04x-%04x%08x".printf(b1, b2, b3, b4, b5_1, b5_2);
}
public abstract class StanzaListener<T> : Object { public abstract class StanzaListener<T> : Object {
public abstract string action_group { get; } public abstract string action_group { get; }
public abstract string[] after_actions { get; } public abstract string[] after_actions { get; }
public abstract async void run(Core.XmppStream stream, T stanza);
public abstract async void run(XmppStream stream, T stanza);
} }
public class StanzaListenerHolder<T> : Object { public class StanzaListenerHolder<T> : Object {
@ -42,14 +32,14 @@ public class StanzaListenerHolder<T> : Object {
resort_list(); resort_list();
} }
public async void run(Core.XmppStream stream, T stanza) { public async void run(XmppStream stream, T stanza) {
foreach (StanzaListener<T> l in listeners) { foreach (StanzaListener<T> l in listeners) {
yield l.run(stream, stanza); yield l.run(stream, stanza);
} }
} }
private bool set_contains_action(Gee.List<StanzaListener<T>> s, string[] actions) { private bool set_contains_action(Gee.List<StanzaListener<T>> s, string[] actions) {
foreach(StanzaListener<T> l in s) { foreach (StanzaListener<T> l in s) {
if (l.action_group in actions) { if (l.action_group in actions) {
return true; return true;
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.DataForms { namespace Xmpp.Xep.DataForms {
public const string NS_URI = "jabber:x:data"; public const string NS_URI = "jabber:x:data";

View file

@ -1,22 +1,20 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.ServiceDiscovery { namespace Xmpp.Xep.ServiceDiscovery {
public class Flag : XmppStreamFlag { public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "service_discovery"); public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "service_discovery");
private HashMap<string, Gee.List<string>?> entity_features = new HashMap<string, Gee.List<string>?>(); private HashMap<Jid, Gee.List<string>?> entity_features = new HashMap<Jid, Gee.List<string>?>(Jid.hash_func, Jid.equals_func);
private HashMap<string, Gee.List<Identity>?> entity_identities = new HashMap<string, Gee.List<Identity>?>(); private HashMap<Jid, Gee.List<Identity>?> entity_identities = new HashMap<Jid, Gee.List<Identity>?>(Jid.hash_func, Jid.equals_func);
private HashMap<string, Gee.List<Item>?> entity_items = new HashMap<string, Gee.List<Item>?>(); private HashMap<Jid, Gee.List<Item>?> entity_items = new HashMap<Jid, Gee.List<Item>?>(Jid.hash_func, Jid.equals_func);
public Gee.List<string> features = new ArrayList<string>(); public Gee.List<string> features = new ArrayList<string>();
public Gee.List<Identity>? get_entity_categories(string jid) { public Gee.List<Identity>? get_entity_categories(Jid jid) {
return entity_identities.has_key(jid) ? entity_identities[jid] : null; // TODO isnt this default for hashmap return entity_identities.has_key(jid) ? entity_identities[jid] : null; // TODO isnt this default for hashmap
} }
public bool? has_entity_identity(string jid, string category, string type) { public bool? has_entity_identity(Jid jid, string category, string type) {
if (!entity_identities.has_key(jid)) return null; if (!entity_identities.has_key(jid)) return null;
if (entity_identities[jid] == null) return false; if (entity_identities[jid] == null) return false;
foreach (Identity identity in entity_identities[jid]) { foreach (Identity identity in entity_identities[jid]) {
@ -25,21 +23,21 @@ public class Flag : XmppStreamFlag {
return false; return false;
} }
public bool? has_entity_feature(string jid, string feature) { public bool? has_entity_feature(Jid jid, string feature) {
if (!entity_features.has_key(jid)) return null; if (!entity_features.has_key(jid)) return null;
if (entity_features[jid] == null) return false; if (entity_features[jid] == null) return false;
return entity_features[jid].contains(feature); return entity_features[jid].contains(feature);
} }
public void set_entity_identities(string jid, Gee.List<Identity>? identities) { public void set_entity_identities(Jid jid, Gee.List<Identity>? identities) {
entity_identities[jid] = identities; entity_identities[jid] = identities;
} }
public void set_entity_features(string jid, Gee.List<string>? features) { public void set_entity_features(Jid jid, Gee.List<string>? features) {
entity_features[jid] = features; entity_features[jid] = features;
} }
public void set_entity_items(string jid, Gee.List<Item>? features) { public void set_entity_items(Jid jid, Gee.List<Item>? features) {
entity_items[jid] = features; entity_items[jid] = features;
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.ServiceDiscovery { namespace Xmpp.Xep.ServiceDiscovery {
public class InfoResult { public class InfoResult {

View file

@ -1,11 +1,11 @@
namespace Xmpp.Xep.ServiceDiscovery { namespace Xmpp.Xep.ServiceDiscovery {
public class Item { public class Item {
public string jid; public Jid jid;
public string? name; public string? name;
public string? node; public string? node;
public Item(string jid, string? name = null, string? node = null) { public Item(Jid jid, string? name = null, string? node = null) {
this.jid = jid; this.jid = jid;
this.name = name; this.name = name;
this.node = node; this.node = node;

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.ServiceDiscovery { namespace Xmpp.Xep.ServiceDiscovery {
public class ItemsResult { public class ItemsResult {
@ -11,7 +9,7 @@ public class ItemsResult {
owned get { owned get {
ArrayList<Item> ret = new ArrayList<Item>(); ArrayList<Item> ret = new ArrayList<Item>();
foreach (StanzaNode feature_node in iq.stanza.get_subnode("query", NS_URI_ITEMS).get_subnodes("item", NS_URI_ITEMS)) { foreach (StanzaNode feature_node in iq.stanza.get_subnode("query", NS_URI_ITEMS).get_subnodes("item", NS_URI_ITEMS)) {
ret.add(new Item(feature_node.get_attribute("jid", NS_URI_ITEMS), ret.add(new Item(Jid.parse(feature_node.get_attribute("jid", NS_URI_ITEMS)),
feature_node.get_attribute("name", NS_URI_ITEMS), feature_node.get_attribute("name", NS_URI_ITEMS),
feature_node.get_attribute("node", NS_URI_ITEMS))); feature_node.get_attribute("node", NS_URI_ITEMS)));
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.ServiceDiscovery { namespace Xmpp.Xep.ServiceDiscovery {
private const string NS_URI = "http://jabber.org/protocol/disco"; private const string NS_URI = "http://jabber.org/protocol/disco";
@ -30,7 +28,7 @@ public class Module : XmppStreamModule, Iq.Handler {
} }
public delegate void HasEntryCategoryRes(XmppStream stream, Gee.List<Identity>? identities); public delegate void HasEntryCategoryRes(XmppStream stream, Gee.List<Identity>? identities);
public void get_entity_categories(XmppStream stream, string jid, owned HasEntryCategoryRes listener) { public void get_entity_categories(XmppStream stream, Jid jid, owned HasEntryCategoryRes listener) {
Gee.List<Identity>? res = stream.get_flag(Flag.IDENTITY).get_entity_categories(jid); Gee.List<Identity>? res = stream.get_flag(Flag.IDENTITY).get_entity_categories(jid);
if (res != null) listener(stream, res); if (res != null) listener(stream, res);
request_info(stream, jid, (stream, query_result) => { request_info(stream, jid, (stream, query_result) => {
@ -39,7 +37,7 @@ public class Module : XmppStreamModule, Iq.Handler {
} }
public delegate void OnInfoResult(XmppStream stream, InfoResult? query_result); public delegate void OnInfoResult(XmppStream stream, InfoResult? query_result);
public void request_info(XmppStream stream, string jid, owned OnInfoResult listener) { public void request_info(XmppStream stream, Jid jid, owned OnInfoResult listener) {
Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_INFO).add_self_xmlns()); Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_INFO).add_self_xmlns());
iq.to = jid; iq.to = jid;
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => { stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => {
@ -51,7 +49,7 @@ public class Module : XmppStreamModule, Iq.Handler {
} }
public delegate void OnItemsResult(XmppStream stream, ItemsResult query_result); public delegate void OnItemsResult(XmppStream stream, ItemsResult query_result);
public void request_items(XmppStream stream, string jid, owned OnItemsResult listener) { public void request_items(XmppStream stream, Jid jid, owned OnItemsResult listener) {
Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_ITEMS).add_self_xmlns()); Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_ITEMS).add_self_xmlns());
iq.to = jid; iq.to = jid;
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => { stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => {

View file

@ -1,128 +1,123 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.Muc { namespace Xmpp.Xep.Muc {
public class Flag : XmppStreamFlag { public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "muc"); public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "muc");
private HashMap<string, Gee.List<Feature>> room_features = new HashMap<string, Gee.List<Feature>>(); private HashMap<Jid, Gee.List<Feature>> room_features = new HashMap<Jid, Gee.List<Feature>>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, string> room_names = new HashMap<string, string>(); private HashMap<Jid, string> room_names = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, string> enter_ids = new HashMap<string, string>(); private HashMap<Jid, string> enter_ids = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, string> own_nicks = new HashMap<string, string>(); private HashMap<Jid, string> own_nicks = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, string> subjects = new HashMap<string, string>(); private HashMap<Jid, string> subjects = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, string> subjects_by = new HashMap<string, string>(); private HashMap<Jid, Jid> subjects_by = new HashMap<Jid, Jid>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, string> occupant_real_jids = new HashMap<string, string>(); private HashMap<Jid, Jid> occupant_real_jids = new HashMap<Jid, Jid>(Jid.hash_func, Jid.equals_bare_func);
private HashMap<string, HashMap<string, Affiliation>> affiliations = new HashMap<string, HashMap<string, Affiliation>>(); private HashMap<Jid, HashMap<Jid, Affiliation>> affiliations = new HashMap<Jid, HashMap<Jid, Affiliation>>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<string, Role> occupant_role = new HashMap<string, Role>(); private HashMap<Jid, Role> occupant_role = new HashMap<Jid, Role>(Jid.hash_func, Jid.equals_func);
public string? get_room_name(string jid) { return room_names.has_key(jid) ? room_names[jid] : null; } public string? get_room_name(Jid muc_jid) { return room_names.has_key(muc_jid.bare_jid) ? room_names[muc_jid.bare_jid] : null; }
public bool has_room_feature(string jid, Feature feature) { public bool has_room_feature(Jid muc_jid, Feature feature) {
return room_features.has_key(jid) && room_features[jid].contains(feature); return room_features.has_key(muc_jid.bare_jid) && room_features[muc_jid.bare_jid].contains(feature);
} }
public string? get_real_jid(string full_jid) { return occupant_real_jids[full_jid]; } public Jid? get_real_jid(Jid full_jid) { return occupant_real_jids[full_jid]; }
public Gee.List<string> get_offline_members(string muc_jid) { public Gee.List<Jid> get_offline_members(Jid muc_jid) {
Gee.List<string> ret = new ArrayList<string>(); Gee.List<Jid> ret = new ArrayList<Jid>(Jid.equals_func);
HashMap<string, Affiliation>? muc_affiliations = affiliations[muc_jid]; HashMap<Jid, Affiliation>? muc_affiliations = affiliations[muc_jid.bare_jid];
if (muc_affiliations != null) { if (muc_affiliations != null) {
foreach (string jid in muc_affiliations.keys) { foreach (Jid jid in muc_affiliations.keys) {
if (!jid.has_prefix(muc_jid)) ret.add(jid); if (!jid.equals_bare(muc_jid)) ret.add(jid);
} }
} }
return ret; return ret;
} }
public Affiliation get_affiliation(string muc_jid, string full_jid) { public Affiliation get_affiliation(Jid muc_jid, Jid full_jid) {
HashMap<string, Affiliation>? muc_affiliations = affiliations[muc_jid]; HashMap<Jid, Affiliation>? muc_affiliations = affiliations[muc_jid.bare_jid];
if (muc_affiliations != null) return muc_affiliations[full_jid]; if (muc_affiliations != null) return muc_affiliations[full_jid];
return Affiliation.NONE; return Affiliation.NONE;
} }
public Role? get_occupant_role(string full_jid) { public Role? get_occupant_role(Jid full_jid) {
if (occupant_role.has_key(full_jid)) return occupant_role[full_jid]; if (occupant_role.has_key(full_jid)) return occupant_role[full_jid];
return Role.NONE; return Role.NONE;
} }
public string? get_muc_nick(string bare_jid) { return own_nicks[bare_jid]; } public string? get_muc_nick(Jid muc_jid) { return own_nicks[muc_jid.bare_jid]; }
public string? get_enter_id(string bare_jid) { return enter_ids[bare_jid]; } public string? get_enter_id(Jid muc_jid) { return enter_ids[muc_jid.bare_jid]; }
public bool is_muc(string jid) { return own_nicks[jid] != null; } public bool is_muc(Jid jid) { return own_nicks[jid] != null; }
public bool is_occupant(string jid) { public bool is_occupant(Jid jid) {
string bare_jid = get_bare_jid(jid); return own_nicks.has_key(jid.bare_jid) || enter_ids.has_key(jid.bare_jid);
return own_nicks.has_key(bare_jid) || enter_ids.has_key(bare_jid);
} }
public bool is_muc_enter_outstanding() { return enter_ids.size != 0; } public bool is_muc_enter_outstanding() { return enter_ids.size != 0; }
public string? get_muc_subject(string bare_jid) { return subjects[bare_jid]; } public string? get_muc_subject(Jid muc_jid) { return subjects[muc_jid.bare_jid]; }
internal void set_room_name(string jid, string name) { internal void set_room_name(Jid muc_jid, string name) {
room_names[jid] = name; room_names[muc_jid.bare_jid] = name;
} }
internal void set_room_features(string jid, Gee.List<Feature> features) { internal void set_room_features(Jid muc_jid, Gee.List<Feature> features) {
room_features[jid] = features; room_features[muc_jid.bare_jid] = features;
} }
internal void set_real_jid(string full_jid, string real_jid) { occupant_real_jids[full_jid] = real_jid; } internal void set_real_jid(Jid full_jid, Jid real_jid) { occupant_real_jids[full_jid] = real_jid; }
internal void set_offline_member(string muc_jid, string real_jid, Affiliation affiliation) { internal void set_offline_member(Jid muc_jid, Jid real_jid, Affiliation affiliation) {
set_affiliation(muc_jid, real_jid, affiliation); set_affiliation(muc_jid.bare_jid, real_jid, affiliation);
} }
internal void set_affiliation(string muc_jid, string full_jid, Affiliation affiliation) { internal void set_affiliation(Jid muc_jid, Jid full_jid, Affiliation affiliation) {
if (!affiliations.has_key(muc_jid)) affiliations[muc_jid] = new HashMap<string, Affiliation>(); if (!affiliations.has_key(muc_jid.bare_jid)) affiliations[muc_jid.bare_jid] = new HashMap<Jid, Affiliation>(Jid.hash_func, Jid.equals_func);
if (affiliation == Affiliation.NONE) { if (affiliation == Affiliation.NONE) {
affiliations[muc_jid].unset(full_jid); affiliations[muc_jid.bare_jid].unset(full_jid);
} else { } else {
affiliations[muc_jid][full_jid] = affiliation; affiliations[muc_jid.bare_jid][full_jid] = affiliation;
} }
} }
internal void set_occupant_role(string full_jid, Role role) { internal void set_occupant_role(Jid full_jid, Role role) {
occupant_role[full_jid] = role; occupant_role[full_jid] = role;
} }
internal void set_muc_subject(string full_jid, string? subject) { internal void set_muc_subject(Jid full_jid, string? subject) {
string bare_jid = get_bare_jid(full_jid); subjects[full_jid.bare_jid] = subject;
subjects[bare_jid] = subject; subjects_by[full_jid.bare_jid] = full_jid;
subjects_by[bare_jid] = full_jid;
} }
internal void start_muc_enter(string bare_jid, string presence_id) { internal void start_muc_enter(Jid jid, string presence_id) {
enter_ids[bare_jid] = presence_id; enter_ids[jid.bare_jid] = presence_id;
} }
internal void finish_muc_enter(string bare_jid, string? nick = null) { internal void finish_muc_enter(Jid jid, string? nick = null) {
if (nick != null) own_nicks[bare_jid] = nick; if (nick != null) own_nicks[jid.bare_jid] = nick;
enter_ids.unset(bare_jid); enter_ids.unset(jid.bare_jid);
} }
internal void left_muc(XmppStream stream, string muc) { internal void left_muc(XmppStream stream, Jid muc_jid) {
own_nicks.unset(muc); own_nicks.unset(muc_jid);
subjects.unset(muc); subjects.unset(muc_jid);
subjects_by.unset(muc); subjects_by.unset(muc_jid);
Gee.List<string>? occupants = stream.get_flag(Presence.Flag.IDENTITY).get_resources(muc); Gee.List<Jid>? occupants = stream.get_flag(Presence.Flag.IDENTITY).get_resources(muc_jid);
if (occupants != null) { if (occupants != null) {
foreach (string occupant in occupants) { foreach (Jid occupant in occupants) {
remove_occupant_info(occupant); remove_occupant_info(occupant);
} }
} }
} }
internal void remove_occupant_info(string full_jid) { internal void remove_occupant_info(Jid jid) {
occupant_real_jids.unset(full_jid); occupant_real_jids.unset(jid);
string bare_jid = get_bare_jid(full_jid); if (affiliations.has_key(jid)) affiliations[jid].unset(jid);
if (affiliations.has_key(full_jid)) affiliations[bare_jid].unset(full_jid); occupant_role.unset(jid);
occupant_role.unset(full_jid);
} }
internal override string get_ns() { return NS_URI; } internal override string get_ns() { return NS_URI; }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.Muc { namespace Xmpp.Xep.Muc {
private const string NS_URI = "http://jabber.org/protocol/muc"; private const string NS_URI = "http://jabber.org/protocol/muc";
@ -58,20 +56,20 @@ public enum Feature {
public class Module : XmppStreamModule { public class Module : XmppStreamModule {
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0045_muc_module"); public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0045_muc_module");
public signal void received_occupant_affiliation(XmppStream stream, string jid, Affiliation? affiliation); public signal void received_occupant_affiliation(XmppStream stream, Jid jid, Affiliation? affiliation);
public signal void received_occupant_jid(XmppStream stream, string jid, string? real_jid); public signal void received_occupant_jid(XmppStream stream, Jid jid, Jid? real_jid);
public signal void received_occupant_role(XmppStream stream, string jid, Role? role); public signal void received_occupant_role(XmppStream stream, Jid jid, Role? role);
public signal void subject_set(XmppStream stream, string subject, string jid); public signal void subject_set(XmppStream stream, string? subject, Jid jid);
public signal void room_configuration_changed(XmppStream stream, string jid, StatusCode code); public signal void room_configuration_changed(XmppStream stream, Jid jid, StatusCode code);
public signal void room_entered(XmppStream stream, string jid, string nick); public signal void room_entered(XmppStream stream, Jid jid, string nick);
public signal void room_enter_error(XmppStream stream, string jid, MucEnterError? error); // TODO "?" shoudln't be necessary (vala bug), remove someday public signal void room_enter_error(XmppStream stream, Jid jid, MucEnterError? error); // TODO "?" shoudln't be necessary (vala bug), remove someday
public signal void self_removed_from_room(XmppStream stream, string jid, StatusCode code); public signal void self_removed_from_room(XmppStream stream, Jid jid, StatusCode code);
public signal void removed_from_room(XmppStream stream, string jid, StatusCode? code); public signal void removed_from_room(XmppStream stream, Jid jid, StatusCode? code);
public void enter(XmppStream stream, string bare_jid, string nick, string? password, DateTime? history_since) { public void enter(XmppStream stream, Jid bare_jid, string nick, string? password, DateTime? history_since) {
Presence.Stanza presence = new Presence.Stanza(); Presence.Stanza presence = new Presence.Stanza();
presence.to = bare_jid + "/" + nick; presence.to = bare_jid.with_resource(nick);
StanzaNode x_node = new StanzaNode.build("x", NS_URI).add_self_xmlns(); StanzaNode x_node = new StanzaNode.build("x", NS_URI).add_self_xmlns();
if (password != null) { if (password != null) {
x_node.put_node(new StanzaNode.build("password", NS_URI).put_node(new StanzaNode.text(password))); x_node.put_node(new StanzaNode.build("password", NS_URI).put_node(new StanzaNode.text(password)));
@ -89,47 +87,47 @@ public class Module : XmppStreamModule {
stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence); stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence);
} }
public void exit(XmppStream stream, string jid) { public void exit(XmppStream stream, Jid jid) {
string nick = stream.get_flag(Flag.IDENTITY).get_muc_nick(jid); string nick = stream.get_flag(Flag.IDENTITY).get_muc_nick(jid);
Presence.Stanza presence = new Presence.Stanza(); Presence.Stanza presence = new Presence.Stanza();
presence.to = jid + "/" + nick; presence.to = jid.with_resource(nick);
presence.type_ = Presence.Stanza.TYPE_UNAVAILABLE; presence.type_ = Presence.Stanza.TYPE_UNAVAILABLE;
stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence); stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence);
} }
public void change_subject(XmppStream stream, string jid, string subject) { public void change_subject(XmppStream stream, Jid jid, string subject) {
Message.Stanza message = new Message.Stanza(); MessageStanza message = new MessageStanza();
message.to = jid; message.to = jid;
message.type_ = Message.Stanza.TYPE_GROUPCHAT; message.type_ = MessageStanza.TYPE_GROUPCHAT;
message.stanza.put_node((new StanzaNode.build("subject")).put_node(new StanzaNode.text(subject))); message.stanza.put_node((new StanzaNode.build("subject")).put_node(new StanzaNode.text(subject)));
stream.get_module(Message.Module.IDENTITY).send_message(stream, message); stream.get_module(MessageModule.IDENTITY).send_message(stream, message);
} }
public void change_nick(XmppStream stream, string jid, string new_nick) { public void change_nick(XmppStream stream, Jid jid, string new_nick) {
Presence.Stanza presence = new Presence.Stanza(); Presence.Stanza presence = new Presence.Stanza();
presence.to = jid + "/" + new_nick; presence.to = jid.with_resource(new_nick);
stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence); stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence);
} }
public void invite(XmppStream stream, string to_muc, string jid) { public void invite(XmppStream stream, Jid to_muc, Jid jid) {
Message.Stanza message = new Message.Stanza(); MessageStanza message = new MessageStanza();
message.to = to_muc; message.to = to_muc;
StanzaNode invite_node = new StanzaNode.build("x", NS_URI_USER).add_self_xmlns() StanzaNode invite_node = new StanzaNode.build("x", NS_URI_USER).add_self_xmlns()
.put_node(new StanzaNode.build("invite", NS_URI_USER).put_attribute("to", jid)); .put_node(new StanzaNode.build("invite", NS_URI_USER).put_attribute("to", jid.to_string()));
message.stanza.put_node(invite_node); message.stanza.put_node(invite_node);
stream.get_module(Message.Module.IDENTITY).send_message(stream, message); stream.get_module(MessageModule.IDENTITY).send_message(stream, message);
} }
public void kick(XmppStream stream, string jid, string nick) { public void kick(XmppStream stream, Jid jid, string nick) {
change_role(stream, jid, nick, "none"); change_role(stream, jid, nick, "none");
} }
/* XEP 0046: "A user cannot be kicked by a moderator with a lower affiliation." (XEP 0045 8.2) */ /* XEP 0046: "A user cannot be kicked by a moderator with a lower affiliation." (XEP 0045 8.2) */
public bool kick_possible(XmppStream stream, string occupant) { public bool kick_possible(XmppStream stream, Jid occupant) {
string muc_jid = get_bare_jid(occupant); Jid muc_jid = occupant.bare_jid;
Flag flag = stream.get_flag(Flag.IDENTITY); Flag flag = stream.get_flag(Flag.IDENTITY);
string own_nick = flag.get_muc_nick(muc_jid); string own_nick = flag.get_muc_nick(muc_jid);
Affiliation my_affiliation = flag.get_affiliation(muc_jid, muc_jid + "/" + own_nick); Affiliation my_affiliation = flag.get_affiliation(muc_jid, muc_jid.with_resource(own_nick));
Affiliation other_affiliation = flag.get_affiliation(muc_jid, occupant); Affiliation other_affiliation = flag.get_affiliation(muc_jid, occupant);
switch (my_affiliation) { switch (my_affiliation) {
case Affiliation.MEMBER: case Affiliation.MEMBER:
@ -142,22 +140,22 @@ public class Module : XmppStreamModule {
return true; return true;
} }
public void change_role(XmppStream stream, string jid, string nick, string new_role) { public void change_role(XmppStream stream, Jid jid, string nick, string new_role) {
StanzaNode query = new StanzaNode.build("query", NS_URI_ADMIN).add_self_xmlns(); StanzaNode query = new StanzaNode.build("query", NS_URI_ADMIN).add_self_xmlns();
query.put_node(new StanzaNode.build("item", NS_URI_ADMIN).put_attribute("nick", nick, NS_URI_ADMIN).put_attribute("role", new_role, NS_URI_ADMIN)); query.put_node(new StanzaNode.build("item", NS_URI_ADMIN).put_attribute("nick", nick, NS_URI_ADMIN).put_attribute("role", new_role, NS_URI_ADMIN));
Iq.Stanza iq = new Iq.Stanza.set(query) { to=jid }; Iq.Stanza iq = new Iq.Stanza.set(query) { to=jid };
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq); stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq);
} }
public void change_affiliation(XmppStream stream, string jid, string nick, string new_affiliation) { public void change_affiliation(XmppStream stream, Jid jid, string nick, string new_affiliation) {
StanzaNode query = new StanzaNode.build("query", NS_URI_ADMIN).add_self_xmlns(); StanzaNode query = new StanzaNode.build("query", NS_URI_ADMIN).add_self_xmlns();
query.put_node(new StanzaNode.build("item", NS_URI_ADMIN).put_attribute("nick", nick, NS_URI_ADMIN).put_attribute("affiliation", new_affiliation, NS_URI_ADMIN)); query.put_node(new StanzaNode.build("item", NS_URI_ADMIN).put_attribute("nick", nick, NS_URI_ADMIN).put_attribute("affiliation", new_affiliation, NS_URI_ADMIN));
Iq.Stanza iq = new Iq.Stanza.set(query) { to=jid }; Iq.Stanza iq = new Iq.Stanza.set(query) { to=jid };
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq); stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq);
} }
public delegate void OnConfigFormResult(XmppStream stream, string jid, DataForms.DataForm data_form); public delegate void OnConfigFormResult(XmppStream stream, Jid jid, DataForms.DataForm data_form);
public void get_config_form(XmppStream stream, string jid, owned OnConfigFormResult listener) { public void get_config_form(XmppStream stream, Jid jid, owned OnConfigFormResult listener) {
Iq.Stanza get_iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_OWNER).add_self_xmlns()) { to=jid }; Iq.Stanza get_iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_OWNER).add_self_xmlns()) { to=jid };
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, get_iq, (stream, form_iq) => { stream.get_module(Iq.Module.IDENTITY).send_iq(stream, get_iq, (stream, form_iq) => {
StanzaNode? x_node = form_iq.stanza.get_deep_subnode(NS_URI_OWNER + ":query", DataForms.NS_URI + ":x"); StanzaNode? x_node = form_iq.stanza.get_deep_subnode(NS_URI_OWNER + ":query", DataForms.NS_URI + ":x");
@ -176,7 +174,7 @@ public class Module : XmppStreamModule {
public override void attach(XmppStream stream) { public override void attach(XmppStream stream) {
stream.add_flag(new Muc.Flag()); stream.add_flag(new Muc.Flag());
stream.get_module(Message.Module.IDENTITY).received_message.connect(on_received_message); stream.get_module(MessageModule.IDENTITY).received_message.connect(on_received_message);
stream.get_module(Presence.Module.IDENTITY).received_presence.connect(check_for_enter_error); stream.get_module(Presence.Module.IDENTITY).received_presence.connect(check_for_enter_error);
stream.get_module(Presence.Module.IDENTITY).received_available.connect(on_received_available); stream.get_module(Presence.Module.IDENTITY).received_available.connect(on_received_available);
stream.get_module(Presence.Module.IDENTITY).received_unavailable.connect(on_received_unavailable); stream.get_module(Presence.Module.IDENTITY).received_unavailable.connect(on_received_unavailable);
@ -192,7 +190,7 @@ public class Module : XmppStreamModule {
} }
public override void detach(XmppStream stream) { public override void detach(XmppStream stream) {
stream.get_module(Message.Module.IDENTITY).received_message.disconnect(on_received_message); stream.get_module(MessageModule.IDENTITY).received_message.disconnect(on_received_message);
stream.get_module(Presence.Module.IDENTITY).received_presence.disconnect(check_for_enter_error); stream.get_module(Presence.Module.IDENTITY).received_presence.disconnect(check_for_enter_error);
stream.get_module(Presence.Module.IDENTITY).received_available.disconnect(on_received_available); stream.get_module(Presence.Module.IDENTITY).received_available.disconnect(on_received_available);
stream.get_module(Presence.Module.IDENTITY).received_unavailable.disconnect(on_received_unavailable); stream.get_module(Presence.Module.IDENTITY).received_unavailable.disconnect(on_received_unavailable);
@ -201,8 +199,8 @@ public class Module : XmppStreamModule {
public override string get_ns() { return NS_URI; } public override string get_ns() { return NS_URI; }
public override string get_id() { return IDENTITY.id; } public override string get_id() { return IDENTITY.id; }
private void on_received_message(XmppStream stream, Message.Stanza message) { private void on_received_message(XmppStream stream, MessageStanza message) {
if (message.type_ == Message.Stanza.TYPE_GROUPCHAT) { if (message.type_ == MessageStanza.TYPE_GROUPCHAT) {
StanzaNode? subject_node = message.stanza.get_subnode("subject"); StanzaNode? subject_node = message.stanza.get_subnode("subject");
if (subject_node != null) { if (subject_node != null) {
string subject = subject_node.get_string_content(); string subject = subject_node.get_string_content();
@ -215,7 +213,7 @@ public class Module : XmppStreamModule {
private void check_for_enter_error(XmppStream stream, Presence.Stanza presence) { private void check_for_enter_error(XmppStream stream, Presence.Stanza presence) {
Flag flag = stream.get_flag(Flag.IDENTITY); Flag flag = stream.get_flag(Flag.IDENTITY);
if (presence.is_error() && flag.is_muc_enter_outstanding() && flag.is_occupant(presence.from)) { if (presence.is_error() && flag.is_muc_enter_outstanding() && flag.is_occupant(presence.from)) {
string bare_jid = get_bare_jid(presence.from); Jid bare_jid = presence.from.bare_jid;
ErrorStanza? error_stanza = presence.get_error(); ErrorStanza? error_stanza = presence.get_error();
if (flag.get_enter_id(bare_jid) == presence.id) { if (flag.get_enter_id(bare_jid) == presence.id) {
MucEnterError error = MucEnterError.NONE; MucEnterError error = MucEnterError.NONE;
@ -258,20 +256,21 @@ public class Module : XmppStreamModule {
if (x_node != null) { if (x_node != null) {
ArrayList<int> status_codes = get_status_codes(x_node); ArrayList<int> status_codes = get_status_codes(x_node);
if (status_codes.contains(StatusCode.SELF_PRESENCE)) { if (status_codes.contains(StatusCode.SELF_PRESENCE)) {
string bare_jid = get_bare_jid(presence.from); Jid bare_jid = presence.from.bare_jid;
if (flag.get_enter_id(bare_jid) != null) { if (flag.get_enter_id(bare_jid) != null) {
room_entered(stream, bare_jid, get_resource_part(presence.from)); room_entered(stream, bare_jid, presence.from.resourcepart);
flag.finish_muc_enter(bare_jid, get_resource_part(presence.from)); flag.finish_muc_enter(bare_jid, presence.from.resourcepart);
} }
} }
string? affiliation_str = x_node.get_deep_attribute("item", "affiliation"); string? affiliation_str = x_node.get_deep_attribute("item", "affiliation");
if (affiliation_str != null) { if (affiliation_str != null) {
Affiliation affiliation = parse_affiliation(affiliation_str); Affiliation affiliation = parse_affiliation(affiliation_str);
flag.set_affiliation(get_bare_jid(presence.from), presence.from, affiliation); flag.set_affiliation(presence.from.bare_jid, presence.from, affiliation);
received_occupant_affiliation(stream, presence.from, affiliation); received_occupant_affiliation(stream, presence.from, affiliation);
} }
string? jid = x_node.get_deep_attribute("item", "jid"); string? jid_ = x_node.get_deep_attribute("item", "jid");
if (jid != null) { if (jid_ != null) {
Jid? jid = Jid.parse(jid_);
flag.set_real_jid(presence.from, jid); flag.set_real_jid(presence.from, jid);
received_occupant_jid(stream, presence.from, jid); received_occupant_jid(stream, presence.from, jid);
} }
@ -301,10 +300,10 @@ public class Module : XmppStreamModule {
foreach (StatusCode code in USER_REMOVED_CODES) { foreach (StatusCode code in USER_REMOVED_CODES) {
if (code in status_codes) { if (code in status_codes) {
if (StatusCode.SELF_PRESENCE in status_codes) { if (StatusCode.SELF_PRESENCE in status_codes) {
flag.left_muc(stream, get_bare_jid(presence.from)); flag.left_muc(stream, presence.from.bare_jid);
self_removed_from_room(stream, presence.from, code); self_removed_from_room(stream, presence.from, code);
Presence.Flag presence_flag = stream.get_flag(Presence.Flag.IDENTITY); Presence.Flag presence_flag = stream.get_flag(Presence.Flag.IDENTITY);
presence_flag.remove_presence(get_bare_jid(presence.from)); presence_flag.remove_presence(presence.from.bare_jid);
} else { } else {
removed_from_room(stream, presence.from, code); removed_from_room(stream, presence.from, code);
} }
@ -312,7 +311,7 @@ public class Module : XmppStreamModule {
} }
} }
private void query_room_info(XmppStream stream, string jid) { private void query_room_info(XmppStream stream, Jid jid) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, jid, (stream, query_result) => { stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, jid, (stream, query_result) => {
Gee.List<Feature> features = new ArrayList<Feature>(); Gee.List<Feature> features = new ArrayList<Feature>();
@ -351,8 +350,8 @@ public class Module : XmppStreamModule {
}); });
} }
public delegate void OnAffiliationResult(XmppStream stream, Gee.List<string> jids); public delegate void OnAffiliationResult(XmppStream stream, Gee.List<Jid> jids);
private void query_affiliation(XmppStream stream, string jid, string affiliation, owned OnAffiliationResult? listener) { private void query_affiliation(XmppStream stream, Jid jid, string affiliation, owned OnAffiliationResult? listener) {
Iq.Stanza iq = new Iq.Stanza.get( Iq.Stanza iq = new Iq.Stanza.get(
new StanzaNode.build("query", NS_URI_ADMIN) new StanzaNode.build("query", NS_URI_ADMIN)
.add_self_xmlns() .add_self_xmlns()
@ -364,9 +363,9 @@ public class Module : XmppStreamModule {
StanzaNode? query_node = iq.stanza.get_subnode("query", NS_URI_ADMIN); StanzaNode? query_node = iq.stanza.get_subnode("query", NS_URI_ADMIN);
if (query_node == null) return; if (query_node == null) return;
Gee.List<StanzaNode> item_nodes = query_node.get_subnodes("item", NS_URI_ADMIN); Gee.List<StanzaNode> item_nodes = query_node.get_subnodes("item", NS_URI_ADMIN);
Gee.List<string> ret_jids = new ArrayList<string>(); Gee.List<Jid> ret_jids = new ArrayList<Jid>(Jid.equals_func);
foreach (StanzaNode item in item_nodes) { foreach (StanzaNode item in item_nodes) {
string? jid_ = item.get_attribute("jid"); Jid? jid_ = Jid.parse(item.get_attribute("jid"));
string? affiliation_ = item.get_attribute("affiliation"); string? affiliation_ = item.get_attribute("affiliation");
if (jid_ != null && affiliation_ != null) { if (jid_ != null && affiliation_ != null) {
stream.get_flag(Muc.Flag.IDENTITY).set_offline_member(iq.from, jid_, parse_affiliation(affiliation_)); stream.get_flag(Muc.Flag.IDENTITY).set_offline_member(iq.from, jid_, parse_affiliation(affiliation_));

View file

@ -1,5 +1,3 @@
using Xmpp.Core;
namespace Xmpp.Xep.Bookmarks { namespace Xmpp.Xep.Bookmarks {
public class Conference : Object { public class Conference : Object {
@ -21,9 +19,10 @@ public class Conference : Object {
set { stanza_node.set_attribute(ATTRIBUTE_AUTOJOIN, value.to_string()); } set { stanza_node.set_attribute(ATTRIBUTE_AUTOJOIN, value.to_string()); }
} }
public string jid { private Jid jid_;
get { return stanza_node.get_attribute(ATTRIBUTE_JID); } public Jid jid {
set { stanza_node.set_attribute(ATTRIBUTE_JID, value); } get { return jid_ ?? (jid_ = Jid.parse(stanza_node.get_attribute(ATTRIBUTE_JID))); }
set { stanza_node.set_attribute(ATTRIBUTE_JID, value.to_string()); }
} }
public string? name { public string? name {
@ -73,7 +72,7 @@ public class Conference : Object {
} }
} }
public Conference(string jid) { public Conference(Jid jid) {
this.stanza_node = new StanzaNode.build("conference", NS_URI); this.stanza_node = new StanzaNode.build("conference", NS_URI);
this.jid = jid; this.jid = jid;
} }
@ -90,4 +89,4 @@ public class Conference : Object {
} }
} }
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.Bookmarks { namespace Xmpp.Xep.Bookmarks {
private const string NS_URI = "storage:bookmarks"; private const string NS_URI = "storage:bookmarks";
@ -10,12 +8,16 @@ public class Module : XmppStreamModule {
public signal void received_conferences(XmppStream stream, Gee.List<Conference> conferences); public signal void received_conferences(XmppStream stream, Gee.List<Conference> conferences);
public delegate void OnResult(XmppStream stream, Gee.List<Conference> conferences); public delegate void OnResult(XmppStream stream, Gee.List<Conference>? conferences);
public void get_conferences(XmppStream stream, owned OnResult listener) { public void get_conferences(XmppStream stream, owned OnResult listener) {
StanzaNode get_node = new StanzaNode.build("storage", NS_URI).add_self_xmlns(); StanzaNode get_node = new StanzaNode.build("storage", NS_URI).add_self_xmlns();
stream.get_module(PrivateXmlStorage.Module.IDENTITY).retrieve(stream, get_node, (stream, node) => { stream.get_module(PrivateXmlStorage.Module.IDENTITY).retrieve(stream, get_node, (stream, node) => {
Gee.List<Conference> conferences = get_conferences_from_stanza(node); if (node == null) {
listener(stream, conferences); listener(stream, null);
} else {
Gee.List<Conference> conferences = get_conferences_from_stanza(node);
listener(stream, conferences);
}
}); });
} }
@ -39,7 +41,7 @@ public class Module : XmppStreamModule {
public void replace_conference(XmppStream stream, Conference orig_conference, Conference modified_conference) { public void replace_conference(XmppStream stream, Conference orig_conference, Conference modified_conference) {
get_conferences(stream, (stream, conferences) => { get_conferences(stream, (stream, conferences) => {
foreach (Conference conference in conferences) { foreach (Conference conference in conferences) {
if (conference.autojoin == orig_conference.autojoin && conference.jid == orig_conference.jid && if (conference.autojoin == orig_conference.autojoin && conference.jid.equals(orig_conference.jid) &&
conference.name == orig_conference.name && conference.nick == orig_conference.nick) { conference.name == orig_conference.name && conference.nick == orig_conference.nick) {
conference.autojoin = modified_conference.autojoin; conference.autojoin = modified_conference.autojoin;
conference.jid = modified_conference.jid; conference.jid = modified_conference.jid;
@ -56,7 +58,7 @@ public class Module : XmppStreamModule {
get_conferences(stream, (stream, conferences) => { get_conferences(stream, (stream, conferences) => {
Conference? rem = null; Conference? rem = null;
foreach (Conference conference in conferences) { foreach (Conference conference in conferences) {
if (conference.name == conference_remove.name && conference.jid == conference_remove.jid && conference.autojoin == conference_remove.autojoin) { if (conference.name == conference_remove.name && conference.jid.equals(conference_remove.jid) && conference.autojoin == conference_remove.autojoin) {
rem = conference; rem = conference;
break; break;
} }

View file

@ -1,7 +1,5 @@
using Gee; using Gee;
using Xmpp.Core;
namespace Xmpp.Xep.PrivateXmlStorage { namespace Xmpp.Xep.PrivateXmlStorage {
private const string NS_URI = "jabber:iq:private"; private const string NS_URI = "jabber:iq:private";
@ -17,7 +15,7 @@ namespace Xmpp.Xep.PrivateXmlStorage {
}); });
} }
public delegate void OnResponse(XmppStream stream, StanzaNode node); public delegate void OnResponse(XmppStream stream, StanzaNode? node);
public void retrieve(XmppStream stream, StanzaNode node, owned OnResponse listener) { public void retrieve(XmppStream stream, StanzaNode node, owned OnResponse listener) {
StanzaNode queryNode = new StanzaNode.build("query", NS_URI).add_self_xmlns().put_node(node); StanzaNode queryNode = new StanzaNode.build("query", NS_URI).add_self_xmlns().put_node(node);
Iq.Stanza iq = new Iq.Stanza.get(queryNode); Iq.Stanza iq = new Iq.Stanza.get(queryNode);

Some files were not shown because too many files have changed in this diff Show more