dino/libdino/src/service/muc_manager.vala

391 lines
18 KiB
Vala
Raw Normal View History

2017-03-02 14:37:32 +00:00
using Gee;
using Xmpp;
using Dino.Entities;
namespace Dino {
public class MucManager : StreamInteractionModule, Object {
public static ModuleIdentity<MucManager> IDENTITY = new ModuleIdentity<MucManager>("muc_manager");
public string id { get { return IDENTITY.id; } }
2017-03-02 14:37:32 +00:00
2017-04-11 16:06:01 +00:00
public signal void joined(Account account, Jid jid, string nick);
public signal void enter_error(Account account, Jid jid, Xep.Muc.MucEnterError error);
2017-04-11 16:06:01 +00:00
public signal void left(Account account, Jid jid);
public signal void subject_set(Account account, Jid jid, string? subject);
public signal void bookmarks_updated(Account account, Gee.List<Xep.Bookmarks.Conference> conferences);
2017-03-02 14:37:32 +00:00
private StreamInteractor stream_interactor;
private HashMap<Jid, Xep.Muc.MucEnterError> enter_errors = new HashMap<Jid, Xep.Muc.MucEnterError>(Jid.hash_func, Jid.equals_func);
private ReceivedMessageListener received_message_listener;
2017-03-02 14:37:32 +00:00
public static void start(StreamInteractor stream_interactor) {
MucManager m = new MucManager(stream_interactor);
stream_interactor.add_module(m);
}
private MucManager(StreamInteractor stream_interactor) {
this.stream_interactor = stream_interactor;
this.received_message_listener = new ReceivedMessageListener(stream_interactor);
2017-03-02 14:37:32 +00:00
stream_interactor.account_added.connect(on_account_added);
stream_interactor.stream_negotiated.connect(on_stream_negotiated);
stream_interactor.get_module(MessageProcessor.IDENTITY).received_pipeline.connect(received_message_listener);
2017-03-02 14:37:32 +00:00
}
2017-04-17 20:46:12 +00:00
public void join(Account account, Jid jid, string? nick, string? password) {
XmppStream? stream = stream_interactor.get_stream(account);
2017-04-11 16:06:01 +00:00
if (stream == null) return;
2017-04-17 20:46:12 +00:00
string nick_ = nick ?? account.bare_jid.localpart ?? account.bare_jid.domainpart;
DateTime? history_since = null;
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account);
if (conversation != null) {
Entities.Message? last_message = stream_interactor.get_module(MessageStorage.IDENTITY).get_last_message(conversation);
if (last_message != null) history_since = last_message.time;
}
stream.get_module(Xep.Muc.Module.IDENTITY).enter(stream, jid.bare_jid, nick_, password, history_since);
2017-03-02 14:37:32 +00:00
}
public void part(Account account, Jid jid) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream == null) return;
unset_autojoin(stream, jid);
stream.get_module(Xep.Muc.Module.IDENTITY).exit(stream, jid.bare_jid);
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account);
if (conversation != null) stream_interactor.get_module(ConversationManager.IDENTITY).close_conversation(conversation);
2017-03-02 14:37:32 +00:00
}
public delegate void OnResult(Jid jid, Xep.DataForms.DataForm data_form);
public void get_config_form(Account account, Jid jid, owned OnResult listener) {
XmppStream? stream = stream_interactor.get_stream(account);
2017-05-30 20:47:16 +00:00
if (stream == null) return;
stream.get_module(Xep.Muc.Module.IDENTITY).get_config_form(stream, jid, (stream, jid, data_form) => {
listener(jid, data_form);
});
2017-05-30 20:47:16 +00:00
}
2017-03-02 14:37:32 +00:00
public void change_subject(Account account, Jid jid, string subject) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_subject(stream, jid.bare_jid, subject);
2017-03-02 14:37:32 +00:00
}
public void change_nick(Account account, Jid jid, string new_nick) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_nick(stream, jid.bare_jid, new_nick);
2017-03-02 14:37:32 +00:00
}
2017-06-11 11:59:24 +00:00
public void invite(Account account, Jid muc, Jid invitee) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).invite(stream, muc.bare_jid, invitee.bare_jid);
2017-06-11 11:59:24 +00:00
}
2017-03-02 14:37:32 +00:00
public void kick(Account account, Jid jid, string nick) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).kick(stream, jid.bare_jid, nick);
2017-03-02 14:37:32 +00:00
}
public void change_affiliation(Account account, Jid jid, string nick, string role) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Muc.Module.IDENTITY).change_affiliation(stream, jid.bare_jid, nick, role);
}
2017-06-11 11:59:24 +00:00
public bool kick_possible(Account account, Jid occupant) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) return stream.get_module(Xep.Muc.Module.IDENTITY).kick_possible(stream, occupant);
2017-06-11 11:59:24 +00:00
return false;
}
public Gee.List<Jid>? get_occupants(Jid jid, Account account) {
2017-03-23 23:15:00 +00:00
if (is_groupchat(jid, account)) {
2018-07-31 15:49:10 +00:00
Gee.List<Jid> ret = new ArrayList<Jid>(Jid.equals_func);
Gee.List<Jid>? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(jid, account);
if (full_jids != null) {
ret.add_all(full_jids);
// Remove eventual presence from bare jid
ret.remove(jid);
}
return ret;
2017-03-23 23:15:00 +00:00
}
return null;
2017-03-02 14:37:32 +00:00
}
public Gee.List<Jid>? get_other_occupants(Jid jid, Account account) {
Gee.List<Jid>? occupants = get_occupants(jid, account);
2017-06-11 11:59:24 +00:00
Jid? own_jid = get_own_jid(jid, account);
if (occupants != null && own_jid != null) {
2018-07-31 15:49:10 +00:00
occupants.remove(own_jid);
2017-03-02 14:37:32 +00:00
}
return occupants;
}
public bool is_groupchat(Jid jid, Account account) {
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account);
return !jid.is_full() && conversation != null && conversation.type_ == Conversation.Type.GROUPCHAT;
2017-03-02 14:37:32 +00:00
}
public bool is_groupchat_occupant(Jid jid, Account account) {
return is_groupchat(jid.bare_jid, account) && jid.is_full();
}
public void get_bookmarks(Account account, owned Xep.Bookmarks.Module.OnResult listener) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (owned)listener);
2017-03-02 14:37:32 +00:00
}
public void add_bookmark(Account account, Xep.Bookmarks.Conference conference) {
XmppStream? stream = stream_interactor.get_stream(account);
2017-03-02 14:37:32 +00:00
if (stream != null) {
2017-03-11 00:40:42 +00:00
stream.get_module(Xep.Bookmarks.Module.IDENTITY).add_conference(stream, conference);
2017-03-02 14:37:32 +00:00
}
}
public void replace_bookmark(Account account, Xep.Bookmarks.Conference was, Xep.Bookmarks.Conference replace) {
XmppStream? stream = stream_interactor.get_stream(account);
2017-03-02 14:37:32 +00:00
if (stream != null) {
2017-03-11 00:40:42 +00:00
stream.get_module(Xep.Bookmarks.Module.IDENTITY).replace_conference(stream, was, replace);
2017-03-02 14:37:32 +00:00
}
}
public void remove_bookmark(Account account, Xep.Bookmarks.Conference conference) {
XmppStream? stream = stream_interactor.get_stream(account);
2017-03-02 14:37:32 +00:00
if (stream != null) {
2017-03-11 00:40:42 +00:00
stream.get_module(Xep.Bookmarks.Module.IDENTITY).remove_conference(stream, conference);
2017-03-02 14:37:32 +00:00
}
}
public string? get_room_name(Account account, Jid jid) {
2018-04-17 18:11:44 +00:00
Xep.Muc.Flag? flag = get_muc_flag(account);
if (flag != null) {
return flag.get_room_name(jid);
}
return null;
}
2017-03-02 14:37:32 +00:00
public string? get_groupchat_subject(Jid jid, Account account) {
2018-04-17 18:11:44 +00:00
Xep.Muc.Flag? flag = get_muc_flag(account);
if (flag != null) {
return flag.get_muc_subject(jid.bare_jid);
2017-03-02 14:37:32 +00:00
}
return null;
}
public Jid? get_real_jid(Jid jid, Account account) {
2018-04-17 18:11:44 +00:00
Xep.Muc.Flag? flag = get_muc_flag(account);
if (flag != null) {
return flag.get_real_jid(jid);
2017-03-02 14:37:32 +00:00
}
return null;
}
2017-06-11 11:59:24 +00:00
public Xep.Muc.Role? get_role(Jid jid, Account account) {
2018-04-17 18:11:44 +00:00
Xep.Muc.Flag? flag = get_muc_flag(account);
if (flag != null) {
return flag.get_occupant_role(jid);
}
2017-06-11 11:59:24 +00:00
return null;
}
2017-05-18 21:14:44 +00:00
public Xep.Muc.Affiliation? get_affiliation(Jid muc_jid, Jid jid, Account account) {
2018-04-17 18:11:44 +00:00
Xep.Muc.Flag? flag = get_muc_flag(account);
if (flag != null) {
return flag.get_affiliation(muc_jid, jid);
}
2017-05-18 21:14:44 +00:00
return null;
}
public Gee.List<Jid>? get_offline_members(Jid jid, Account account) {
2018-04-17 18:11:44 +00:00
Xep.Muc.Flag? flag = get_muc_flag(account);
if (flag != null) {
return flag.get_offline_members(jid);
2017-05-18 21:14:44 +00:00
}
return null;
2017-05-18 21:14:44 +00:00
}
2017-06-11 11:59:24 +00:00
public Jid? get_own_jid(Jid muc_jid, Account account) {
2018-04-17 18:11:44 +00:00
Xep.Muc.Flag? flag = get_muc_flag(account);
if (flag != null) {
string? nick = flag.get_muc_nick(muc_jid);
if (nick != null) return muc_jid.with_resource(nick);
2017-03-02 14:37:32 +00:00
}
return null;
}
2018-07-31 15:49:10 +00:00
public bool has_avatar(Jid muc_jid, Account account) {
Gee.List<Jid>? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(muc_jid, account);
return full_jids != null && full_jids.contains(muc_jid);
}
2018-04-17 18:11:44 +00:00
private Xep.Muc.Flag? get_muc_flag(Account account) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) {
return stream.get_flag(Xep.Muc.Flag.IDENTITY);
}
return null;
}
2017-04-11 16:06:01 +00:00
public bool is_joined(Jid jid, Account account) {
2017-06-11 11:59:24 +00:00
return get_own_jid(jid, account) != null;
2017-04-11 16:06:01 +00:00
}
2017-03-02 14:37:32 +00:00
private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_entered.connect( (stream, jid, nick) => {
on_room_entred(account, stream, jid, nick);
2017-04-11 16:06:01 +00:00
});
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_enter_error.connect( (stream, jid, error) => {
enter_errors[jid] = error;
enter_error(account, jid, error);
});
2017-04-11 16:06:01 +00:00
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).self_removed_from_room.connect( (stream, jid, code) => {
left(account, jid);
2017-04-11 16:06:01 +00:00
});
2017-03-10 20:45:56 +00:00
stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).subject_set.connect( (stream, subject, jid) => {
subject_set(account, jid, subject);
2017-03-02 14:37:32 +00:00
});
stream_interactor.module_manager.get_module(account, Xep.Bookmarks.Module.IDENTITY).received_conferences.connect( (stream, conferences) => {
sync_autojoin_active(account, conferences);
2017-03-02 14:37:32 +00:00
bookmarks_updated(account, conferences);
});
}
private void on_stream_negotiated(Account account, XmppStream stream) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
if (conferences == null) {
join_all_active(account);
} else {
foreach (Xep.Bookmarks.Conference bookmark in conferences) {
if (bookmark.autojoin) {
join(account, bookmark.jid, bookmark.nick, bookmark.password);
}
2017-04-11 16:06:01 +00:00
}
}
});
2017-03-02 14:37:32 +00:00
}
private void on_room_entred(Account account, XmppStream stream, Jid jid, string nick) {
enter_errors.unset(jid);
set_autojoin(stream, jid, nick, null); // TODO password
joined(account, jid, nick);
stream_interactor.get_module(MessageProcessor.IDENTITY).send_unsent_messages(account, jid);
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(jid, account, Conversation.Type.GROUPCHAT);
stream_interactor.get_module(ConversationManager.IDENTITY).start_conversation(conversation);
conversation.nickname = nick;
}
private void join_all_active(Account account) {
Gee.List<Conversation> conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account);
foreach (Conversation conversation in conversations) {
if (conversation.type_ == Conversation.Type.GROUPCHAT && conversation.nickname != null) {
join(account, conversation.counterpart, conversation.nickname, null);
}
}
}
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(account);
leave_non_autojoin(account, conferences, conversations);
join_autojoin(account, conferences, conversations);
}
private void leave_non_autojoin(Account account, Gee.List<Xep.Bookmarks.Conference> conferences, Gee.List<Conversation> conversations) {
foreach (Conversation conversation in conversations) {
if (conversation.type_ != Conversation.Type.GROUPCHAT || !conversation.account.equals(account)) continue;
bool is_autojoin = false;
foreach (Xep.Bookmarks.Conference conference in conferences) {
if (conference.jid.equals(conversation.counterpart)) {
if (conference.autojoin) is_autojoin = true;
}
}
if (!is_autojoin) {
part(account, conversation.counterpart);
}
}
}
private void join_autojoin(Account account, Gee.List<Xep.Bookmarks.Conference> conferences, Gee.List<Conversation> conversations) {
foreach (Xep.Bookmarks.Conference conference in conferences) {
if (!conference.autojoin) continue;
bool is_active = false;
foreach (Conversation conversation in conversations) {
if (conference.jid.equals(conversation.counterpart)) is_active = true;
}
if (!is_active) {
join(account, conference.jid, conference.nick, conference.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) => {
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) {
if (conference.jid.equals_bare(jid) && conference.nick == nick && conference.password == password) {
if (!conference.autojoin) {
2018-01-16 15:16:43 +00:00
conference.autojoin = true;
stream.get_module(Xep.Bookmarks.Module.IDENTITY).set_conferences(stream, conferences);
}
return;
}
}
stream.get_module(Xep.Bookmarks.Module.IDENTITY).add_conference(stream, changed);
});
}
private void unset_autojoin(XmppStream stream, Jid jid) {
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
if (conferences == null) return;
foreach (Xep.Bookmarks.Conference conference in conferences) {
if (conference.jid.equals_bare(jid)) {
if (conference.autojoin) {
2018-01-16 15:16:43 +00:00
conference.autojoin = false;
stream.get_module(Xep.Bookmarks.Module.IDENTITY).set_conferences(stream, conferences);
return;
}
}
}
});
}
private class ReceivedMessageListener : MessageListener {
2018-01-30 16:29:54 +00:00
public string[] after_actions_const = new string[]{ };
public override string action_group { get { return "MUC"; } }
public override string[] after_actions { get { return after_actions_const; } }
private StreamInteractor stream_interactor;
public ReceivedMessageListener(StreamInteractor stream_interactor) {
this.stream_interactor = stream_interactor;
}
public override async bool run(Entities.Message message, Xmpp.MessageStanza stanza, Conversation conversation) {
if (conversation.type_ != Conversation.Type.GROUPCHAT) return false;
XmppStream stream = stream_interactor.get_stream(conversation.account);
if (stream == null) return false;
if (Xep.DelayedDelivery.MessageFlag.get_flag(message.stanza) == null) {
Jid? real_jid = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_real_jid(message.counterpart);
if (real_jid != null && !real_jid.equals(message.counterpart)) {
message.real_jid = real_jid.bare_jid;
}
}
Jid? own_muc_jid = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(message.counterpart.bare_jid, conversation.account);
if (own_muc_jid != null && message.from.equals(own_muc_jid)) {
Gee.List<Entities.Message> messages = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages(conversation);
foreach (Entities.Message m in messages) { // TODO not here
if (m.equals(message)) {
// For own messages from this device (msg is a duplicate)
m.marked = Message.Marked.RECEIVED;
}
}
// For own messages from other devices (msg is not a duplicate msg)
message.marked = Message.Marked.RECEIVED;
}
return false;
}
}
2017-03-02 14:37:32 +00:00
}
}