Member affiliation in occupant list
This commit is contained in:
parent
b09a056a13
commit
4247922e8c
|
@ -132,6 +132,27 @@ public class MucManager : StreamInteractionModule, Object {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Xep.Muc.Affiliation? get_affiliation(Jid muc_jid, Jid jid, Account account) {
|
||||||
|
Core.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());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gee.List<Jid>? get_offline_members(Jid jid, Account account) {
|
||||||
|
Gee.List<Jid> ret = new ArrayList<Jid>(Jid.equals_func);
|
||||||
|
Core.XmppStream? stream = stream_interactor.get_stream(account);
|
||||||
|
if (stream != null) {
|
||||||
|
Gee.List<string>? members = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_offline_members(jid.to_string());
|
||||||
|
if (members == null) return null;
|
||||||
|
foreach (string member in members) {
|
||||||
|
ret.add(new Jid(member));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
public Jid? get_message_real_jid(Entities.Message message) {
|
public Jid? get_message_real_jid(Entities.Message message) {
|
||||||
if (message.real_jid != null) {
|
if (message.real_jid != null) {
|
||||||
return new Jid(message.real_jid);
|
return new Jid(message.real_jid);
|
||||||
|
|
|
@ -83,11 +83,41 @@ public class List : Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void header(ListBoxRow row, ListBoxRow? before_row) {
|
private void header(ListBoxRow row, ListBoxRow? before_row) {
|
||||||
if (row.get_header() == null && before_row != null) {
|
ListRow c1 = row as ListRow;
|
||||||
row.set_header(new Separator(Orientation.HORIZONTAL));
|
Xmpp.Xep.Muc.Affiliation a1 = stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c1.jid, c1.account);
|
||||||
|
if (before_row != null) {
|
||||||
|
ListRow c2 = before_row as ListRow;
|
||||||
|
Xmpp.Xep.Muc.Affiliation a2 = stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c2.jid, c2.account);
|
||||||
|
if (a1 != a2) {
|
||||||
|
row.set_header(generate_header_widget(a1, false));
|
||||||
|
} else if (row.get_header() != null){
|
||||||
|
row.set_header(null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
row.set_header(generate_header_widget(a1, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Widget generate_header_widget(Xmpp.Xep.Muc.Affiliation affiliation, bool top) {
|
||||||
|
string aff_str;
|
||||||
|
switch (affiliation) {
|
||||||
|
case Xmpp.Xep.Muc.Affiliation.OWNER:
|
||||||
|
aff_str = _("Owner"); break;
|
||||||
|
case Xmpp.Xep.Muc.Affiliation.ADMIN:
|
||||||
|
aff_str = _("Admin"); break;
|
||||||
|
case Xmpp.Xep.Muc.Affiliation.MEMBER:
|
||||||
|
aff_str = _("Member"); break;
|
||||||
|
default:
|
||||||
|
aff_str = _("User"); break;
|
||||||
|
}
|
||||||
|
Box box = new Box(Orientation.VERTICAL, 0) { visible=true };
|
||||||
|
Label label = new Label("") { margin_left=10, margin_top=top?5:15, xalign=0, visible=true };
|
||||||
|
label.set_markup(@"<b>$(Markup.escape_text(aff_str))</b>");
|
||||||
|
box.add(label);
|
||||||
|
box.add(new Separator(Orientation.HORIZONTAL) { visible=true });
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
private bool filter(ListBoxRow r) {
|
private bool filter(ListBoxRow r) {
|
||||||
if (r.get_type().is_a(typeof(ListRow))) {
|
if (r.get_type().is_a(typeof(ListRow))) {
|
||||||
ListRow row = r as ListRow;
|
ListRow row = r as ListRow;
|
||||||
|
@ -102,10 +132,27 @@ public class List : Box {
|
||||||
if (row1.get_type().is_a(typeof(ListRow)) && row2.get_type().is_a(typeof(ListRow))) {
|
if (row1.get_type().is_a(typeof(ListRow)) && row2.get_type().is_a(typeof(ListRow))) {
|
||||||
ListRow c1 = row1 as ListRow;
|
ListRow c1 = row1 as ListRow;
|
||||||
ListRow c2 = row2 as ListRow;
|
ListRow c2 = row2 as ListRow;
|
||||||
return c1.name_label.label.collate(c2.name_label.label);
|
int affiliation1 = get_affiliation_ranking(stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c1.jid, c1.account) ?? Xmpp.Xep.Muc.Affiliation.NONE);
|
||||||
|
int affiliation2 = get_affiliation_ranking(stream_interactor.get_module(MucManager.IDENTITY).get_affiliation(conversation.counterpart, c2.jid, c2.account) ?? Xmpp.Xep.Muc.Affiliation.NONE);
|
||||||
|
if (affiliation1 < affiliation2) return -1;
|
||||||
|
else if (affiliation1 > affiliation2) return 1;
|
||||||
|
else return c1.name_label.label.collate(c2.name_label.label);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int get_affiliation_ranking(Xmpp.Xep.Muc.Affiliation affiliation) {
|
||||||
|
switch (affiliation) {
|
||||||
|
case Xmpp.Xep.Muc.Affiliation.OWNER:
|
||||||
|
return 1;
|
||||||
|
case Xmpp.Xep.Muc.Affiliation.ADMIN:
|
||||||
|
return 2;
|
||||||
|
case Xmpp.Xep.Muc.Affiliation.MEMBER:
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -11,21 +11,32 @@ public class Flag : XmppStreamFlag {
|
||||||
private HashMap<string, string> own_nicks = new HashMap<string, string>();
|
private HashMap<string, string> own_nicks = new HashMap<string, string>();
|
||||||
private HashMap<string, string> subjects = new HashMap<string, string>();
|
private HashMap<string, string> subjects = new HashMap<string, string>();
|
||||||
private HashMap<string, string> subjects_by = new HashMap<string, string>();
|
private HashMap<string, string> subjects_by = new HashMap<string, string>();
|
||||||
|
|
||||||
private HashMap<string, string> occupant_real_jids = new HashMap<string, string>();
|
private HashMap<string, string> occupant_real_jids = new HashMap<string, string>();
|
||||||
private HashMap<string, string> occupant_affiliation = new HashMap<string, string>();
|
private HashMap<string, HashMap<string, Affiliation>> affiliations = new HashMap<string, HashMap<string, Affiliation>>();
|
||||||
private HashMap<string, string> occupant_role = new HashMap<string, string>();
|
private HashMap<string, Role> occupant_role = new HashMap<string, Role>();
|
||||||
|
|
||||||
public string? get_real_jid(string full_jid) { return occupant_real_jids[full_jid]; }
|
public string? get_real_jid(string full_jid) { return occupant_real_jids[full_jid]; }
|
||||||
|
|
||||||
public void set_real_jid(string full_jid, string real_jid) { occupant_real_jids[full_jid] = real_jid; }
|
public Gee.List<string> get_offline_members(string full_jid) {
|
||||||
|
Gee.List<string> ret = new ArrayList<string>();
|
||||||
|
foreach (string muc_jid in affiliations.keys) {
|
||||||
|
foreach (string jid in affiliations[muc_jid].keys) {
|
||||||
|
if (!jid.has_prefix(muc_jid)) ret.add(jid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
public string? get_occupant_affiliation(string full_jid) { return occupant_affiliation[full_jid]; }
|
public Affiliation? get_affiliation(string muc_jid, string full_jid) {
|
||||||
|
if (affiliations.has_key(muc_jid) && affiliations[muc_jid].has_key(full_jid)) return affiliations[muc_jid][full_jid];
|
||||||
|
return Affiliation.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
public void set_occupant_affiliation(string full_jid, string affiliation) { occupant_affiliation[full_jid] = affiliation; }
|
public Role? get_occupant_role(string full_jid) {
|
||||||
|
if (occupant_role.has_key(full_jid)) return occupant_role[full_jid];
|
||||||
public string? get_occupant_role(string full_jid) { return occupant_role[full_jid]; }
|
return Role.NONE;
|
||||||
|
}
|
||||||
public void set_occupant_role(string full_jid, string role) { occupant_role[full_jid] = role; }
|
|
||||||
|
|
||||||
public string? get_muc_nick(string bare_jid) { return own_nicks[bare_jid]; }
|
public string? get_muc_nick(string bare_jid) { return own_nicks[bare_jid]; }
|
||||||
|
|
||||||
|
@ -42,22 +53,41 @@ public class Flag : XmppStreamFlag {
|
||||||
|
|
||||||
public string? get_muc_subject(string bare_jid) { return subjects[bare_jid]; }
|
public string? get_muc_subject(string bare_jid) { return subjects[bare_jid]; }
|
||||||
|
|
||||||
public void set_muc_subject(string full_jid, string? subject) {
|
internal void set_real_jid(string full_jid, string real_jid) { occupant_real_jids[full_jid] = real_jid; }
|
||||||
|
|
||||||
|
internal void set_offline_member(string muc_jid, string real_jid, Affiliation affiliation) {
|
||||||
|
set_affiliation(muc_jid, real_jid, affiliation);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void set_affiliation(string muc_jid, string full_jid, Affiliation affiliation) {
|
||||||
|
if (!affiliations.has_key(muc_jid)) affiliations[muc_jid] = new HashMap<string, Affiliation>();
|
||||||
|
if (affiliation == Affiliation.NONE) {
|
||||||
|
affiliations[muc_jid].unset(full_jid);
|
||||||
|
} else {
|
||||||
|
affiliations[muc_jid][full_jid] = affiliation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void set_occupant_role(string full_jid, Role role) {
|
||||||
|
occupant_role[full_jid] = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void set_muc_subject(string full_jid, string? subject) {
|
||||||
string bare_jid = get_bare_jid(full_jid);
|
string bare_jid = get_bare_jid(full_jid);
|
||||||
subjects[bare_jid] = subject;
|
subjects[bare_jid] = subject;
|
||||||
subjects_by[bare_jid] = full_jid;
|
subjects_by[bare_jid] = full_jid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start_muc_enter(string bare_jid, string presence_id) {
|
internal void start_muc_enter(string bare_jid, string presence_id) {
|
||||||
enter_ids[bare_jid] = presence_id;
|
enter_ids[bare_jid] = presence_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish_muc_enter(string bare_jid, string? nick = null) {
|
internal void finish_muc_enter(string bare_jid, string? nick = null) {
|
||||||
if (nick != null) own_nicks[bare_jid] = nick;
|
if (nick != null) own_nicks[bare_jid] = nick;
|
||||||
enter_ids.unset(bare_jid);
|
enter_ids.unset(bare_jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void left_muc(XmppStream stream, string muc) {
|
internal void left_muc(XmppStream stream, string muc) {
|
||||||
own_nicks.unset(muc);
|
own_nicks.unset(muc);
|
||||||
subjects.unset(muc);
|
subjects.unset(muc);
|
||||||
subjects_by.unset(muc);
|
subjects_by.unset(muc);
|
||||||
|
@ -69,15 +99,16 @@ public class Flag : XmppStreamFlag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove_occupant_info(string full_jid) {
|
internal void remove_occupant_info(string full_jid) {
|
||||||
occupant_real_jids.unset(full_jid);
|
occupant_real_jids.unset(full_jid);
|
||||||
occupant_affiliation.unset(full_jid);
|
string bare_jid = get_bare_jid(full_jid);
|
||||||
|
if (affiliations.has_key(full_jid)) affiliations[bare_jid].unset(full_jid);
|
||||||
occupant_role.unset(full_jid);
|
occupant_role.unset(full_jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string get_ns() { return NS_URI; }
|
internal override string get_ns() { return NS_URI; }
|
||||||
|
|
||||||
public override string get_id() { return IDENTITY.id; }
|
internal override string get_id() { return IDENTITY.id; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,17 +8,6 @@ private const string NS_URI = "http://jabber.org/protocol/muc";
|
||||||
private const string NS_URI_ADMIN = NS_URI + "#admin";
|
private const string NS_URI_ADMIN = NS_URI + "#admin";
|
||||||
private const string NS_URI_USER = NS_URI + "#user";
|
private const string NS_URI_USER = NS_URI + "#user";
|
||||||
|
|
||||||
public const string AFFILIATION_ADMIN = "admin";
|
|
||||||
public const string AFFILIATION_MEMBER = "member";
|
|
||||||
public const string AFFILIATION_NONE = "none";
|
|
||||||
public const string AFFILIATION_OUTCAST = "outcast";
|
|
||||||
public const string AFFILIATION_OWNER = "owner";
|
|
||||||
|
|
||||||
public const string ROLE_MODERATOR = "moderator";
|
|
||||||
public const string ROLE_NONE = "none";
|
|
||||||
public const string ROLE_PARTICIPANT = "participant";
|
|
||||||
public const string ROLE_VISITOR = "visitor";
|
|
||||||
|
|
||||||
public enum MucEnterError {
|
public enum MucEnterError {
|
||||||
PASSWORD_REQUIRED,
|
PASSWORD_REQUIRED,
|
||||||
NOT_IN_MEMBER_LIST,
|
NOT_IN_MEMBER_LIST,
|
||||||
|
@ -28,12 +17,27 @@ public enum MucEnterError {
|
||||||
ROOM_DOESNT_EXIST
|
ROOM_DOESNT_EXIST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Affiliation {
|
||||||
|
ADMIN,
|
||||||
|
MEMBER,
|
||||||
|
NONE,
|
||||||
|
OUTCAST,
|
||||||
|
OWNER
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Role {
|
||||||
|
MODERATOR,
|
||||||
|
NONE,
|
||||||
|
PARTICIPANT,
|
||||||
|
VISITOR
|
||||||
|
}
|
||||||
|
|
||||||
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, string? affiliation);
|
public signal void received_occupant_affiliation(XmppStream stream, string jid, Affiliation? affiliation);
|
||||||
public signal void received_occupant_jid(XmppStream stream, string jid, string? real_jid);
|
public signal void received_occupant_jid(XmppStream stream, string jid, string? real_jid);
|
||||||
public signal void received_occupant_role(XmppStream stream, string jid, string? role);
|
public signal void received_occupant_role(XmppStream stream, string jid, Role? role);
|
||||||
public signal void subject_set(XmppStream stream, string subject, string jid);
|
public signal void subject_set(XmppStream stream, string subject, string jid);
|
||||||
public signal void room_configuration_changed(XmppStream stream, string jid, StatusCode code);
|
public signal void room_configuration_changed(XmppStream stream, string jid, StatusCode code);
|
||||||
|
|
||||||
|
@ -92,6 +96,12 @@ public class Module : XmppStreamModule {
|
||||||
if (stream.get_module(ServiceDiscovery.Module.IDENTITY) != null) {
|
if (stream.get_module(ServiceDiscovery.Module.IDENTITY) != null) {
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
|
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
room_entered.connect((stream, jid, nick) => {
|
||||||
|
query_affiliation(stream, jid, "member", null, null);
|
||||||
|
query_affiliation(stream, jid, "admin", null, null);
|
||||||
|
query_affiliation(stream, jid, "owner", null, null);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void detach(XmppStream stream) {
|
public override void detach(XmppStream stream) {
|
||||||
|
@ -167,8 +177,10 @@ public class Module : XmppStreamModule {
|
||||||
flag.finish_muc_enter(bare_jid, get_resource_part(presence.from));
|
flag.finish_muc_enter(bare_jid, get_resource_part(presence.from));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string? affiliation = x_node.get_deep_attribute("item", "affiliation");
|
string? affiliation_str = x_node.get_deep_attribute("item", "affiliation");
|
||||||
if (affiliation != null) {
|
if (affiliation_str != null) {
|
||||||
|
Affiliation affiliation = parse_affiliation(affiliation_str);
|
||||||
|
flag.set_affiliation(get_bare_jid(presence.from), 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");
|
||||||
|
@ -176,8 +188,10 @@ public class Module : XmppStreamModule {
|
||||||
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);
|
||||||
}
|
}
|
||||||
string? role = x_node.get_deep_attribute("item", "role");
|
string? role_str = x_node.get_deep_attribute("item", "role");
|
||||||
if (role != null) {
|
if (role_str != null) {
|
||||||
|
Role role = parse_role(role_str);
|
||||||
|
flag.set_occupant_role(presence.from, role);
|
||||||
received_occupant_role(stream, presence.from, role);
|
received_occupant_role(stream, presence.from, role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,13 +225,72 @@ public class Module : XmppStreamModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<int> get_status_codes(StanzaNode x_node) {
|
[CCode (has_target = false)] public delegate void OnResult(XmppStream stream, Gee.List<string> jids, Object? store);
|
||||||
|
private void query_affiliation(XmppStream stream, string jid, string affiliation, OnResult? on_result, Object? store) {
|
||||||
|
Iq.Stanza iq = new Iq.Stanza.get(
|
||||||
|
new StanzaNode.build("query", NS_URI_ADMIN)
|
||||||
|
.add_self_xmlns()
|
||||||
|
.put_node(new StanzaNode.build("item", NS_URI_ADMIN)
|
||||||
|
.put_attribute("affiliation", affiliation))
|
||||||
|
) { to=jid };
|
||||||
|
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq, store) => {
|
||||||
|
Tuple<OnResult?, Object?> tuple = store as Tuple<OnResult?, Object?>;
|
||||||
|
if (iq.is_error()) return;
|
||||||
|
StanzaNode? query_node = iq.stanza.get_subnode("query", NS_URI_ADMIN);
|
||||||
|
if (query_node == null) return;
|
||||||
|
Gee.List<StanzaNode> item_nodes = query_node.get_subnodes("item", NS_URI_ADMIN);
|
||||||
|
Gee.List<string> ret_jids = new ArrayList<string>();
|
||||||
|
foreach (StanzaNode item in item_nodes) {
|
||||||
|
string? jid_ = item.get_attribute("jid");
|
||||||
|
string? affiliation_ = item.get_attribute("affiliation");
|
||||||
|
if (jid_ != null && affiliation_ != null) {
|
||||||
|
stream.get_flag(Muc.Flag.IDENTITY).set_offline_member(iq.from, jid_, parse_affiliation(affiliation_));
|
||||||
|
ret_jids.add(jid_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tuple.a != null) tuple.a(stream, ret_jids, tuple.b);
|
||||||
|
}, Tuple.create(on_result, store));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ArrayList<int> get_status_codes(StanzaNode x_node) {
|
||||||
ArrayList<int> ret = new ArrayList<int>();
|
ArrayList<int> ret = new ArrayList<int>();
|
||||||
foreach (StanzaNode status_node in x_node.get_subnodes("status", NS_URI_USER)) {
|
foreach (StanzaNode status_node in x_node.get_subnodes("status", NS_URI_USER)) {
|
||||||
ret.add(int.parse(status_node.get_attribute("code")));
|
ret.add(int.parse(status_node.get_attribute("code")));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Affiliation parse_affiliation(string affiliation_str) {
|
||||||
|
Affiliation affiliation;
|
||||||
|
switch (affiliation_str) {
|
||||||
|
case "admin":
|
||||||
|
affiliation = Affiliation.ADMIN; break;
|
||||||
|
case "member":
|
||||||
|
affiliation = Affiliation.MEMBER; break;
|
||||||
|
case "outcast":
|
||||||
|
affiliation = Affiliation.OUTCAST; break;
|
||||||
|
case "owner":
|
||||||
|
affiliation = Affiliation.OWNER; break;
|
||||||
|
default:
|
||||||
|
affiliation = Affiliation.NONE; break;
|
||||||
|
}
|
||||||
|
return affiliation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Role parse_role(string role_str) {
|
||||||
|
Role role;
|
||||||
|
switch (role_str) {
|
||||||
|
case "moderator":
|
||||||
|
role = Role.MODERATOR; break;
|
||||||
|
case "participant":
|
||||||
|
role = Role.PARTICIPANT; break;
|
||||||
|
case "visitor":
|
||||||
|
role = Role.VISITOR; break;
|
||||||
|
default:
|
||||||
|
role = Role.NONE; break;
|
||||||
|
}
|
||||||
|
return role;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue