Add Bookmarks2 implementation, introduce bookmarks interfaces
This commit is contained in:
parent
1287135ebb
commit
74c29d4df1
|
@ -62,6 +62,7 @@ public class ModuleManager {
|
||||||
module_map[account].add(new Xep.ServiceDiscovery.Module.with_identity("client", "pc"));
|
module_map[account].add(new Xep.ServiceDiscovery.Module.with_identity("client", "pc"));
|
||||||
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 Xep.Bookmarks2.Module());
|
||||||
module_map[account].add(new Presence.Module());
|
module_map[account].add(new Presence.Module());
|
||||||
module_map[account].add(new Xmpp.MessageModule());
|
module_map[account].add(new Xmpp.MessageModule());
|
||||||
module_map[account].add(new Xep.MessageArchiveManagement.Module());
|
module_map[account].add(new Xep.MessageArchiveManagement.Module());
|
||||||
|
|
|
@ -14,13 +14,15 @@ public class MucManager : StreamInteractionModule, Object {
|
||||||
public signal void subject_set(Account account, Jid jid, string? subject);
|
public signal void subject_set(Account account, Jid jid, string? subject);
|
||||||
public signal void room_name_set(Account account, Jid jid, string? room_name);
|
public signal void room_name_set(Account account, Jid jid, string? room_name);
|
||||||
public signal void private_room_occupant_updated(Account account, Jid room, Jid occupant);
|
public signal void private_room_occupant_updated(Account account, Jid room, Jid occupant);
|
||||||
public signal void bookmarks_updated(Account account, Gee.List<Xep.Bookmarks.Conference> conferences);
|
|
||||||
public signal void invite_received(Account account, Jid room_jid, Jid from_jid, string? password, string? reason);
|
public signal void invite_received(Account account, Jid room_jid, Jid from_jid, string? password, string? reason);
|
||||||
|
public signal void bookmarks_updated(Account account, Set<Conference> conferences);
|
||||||
|
public signal void conference_added(Account account, Conference conference);
|
||||||
|
public signal void conference_removed(Account account, Jid jid);
|
||||||
|
|
||||||
private StreamInteractor stream_interactor;
|
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 HashMap<Jid, Xep.Muc.MucEnterError> enter_errors = new HashMap<Jid, Xep.Muc.MucEnterError>(Jid.hash_func, Jid.equals_func);
|
||||||
private ReceivedMessageListener received_message_listener;
|
private ReceivedMessageListener received_message_listener;
|
||||||
|
private HashMap<Account, BookmarksProvider> bookmarks_provider = new HashMap<Account, BookmarksProvider>(Account.hash_func, Account.equals_func);
|
||||||
public static void start(StreamInteractor stream_interactor) {
|
public static void start(StreamInteractor stream_interactor) {
|
||||||
MucManager m = new MucManager(stream_interactor);
|
MucManager m = new MucManager(stream_interactor);
|
||||||
stream_interactor.add_module(m);
|
stream_interactor.add_module(m);
|
||||||
|
@ -52,7 +54,7 @@ public class MucManager : StreamInteractionModule, Object {
|
||||||
public void part(Account account, Jid jid) {
|
public void part(Account account, Jid jid) {
|
||||||
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(account, stream, jid);
|
||||||
stream.get_module(Xep.Muc.Module.IDENTITY).exit(stream, jid.bare_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);
|
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(jid, account);
|
||||||
|
@ -148,29 +150,31 @@ public class MucManager : StreamInteractionModule, Object {
|
||||||
return is_groupchat(jid.bare_jid, account) && jid.resourcepart != null;
|
return is_groupchat(jid.bare_jid, account) && jid.resourcepart != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void get_bookmarks(Account account, owned Xep.Bookmarks.Module.OnResult listener) {
|
public async Set<Conference>? get_bookmarks(Account account) {
|
||||||
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) return null;
|
||||||
|
|
||||||
|
return yield bookmarks_provider[account].get_conferences(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add_bookmark(Account account, Xep.Bookmarks.Conference conference) {
|
public void add_bookmark(Account account, Conference conference) {
|
||||||
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);
|
bookmarks_provider[account].add_conference.begin(stream, conference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replace_bookmark(Account account, Xep.Bookmarks.Conference was, Xep.Bookmarks.Conference replace) {
|
public void replace_bookmark(Account account, Conference was, Conference replace) {
|
||||||
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.begin(stream, was, replace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove_bookmark(Account account, Xep.Bookmarks.Conference conference) {
|
public void remove_bookmark(Account account, Conference conference) {
|
||||||
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);
|
bookmarks_provider[account].remove_conference.begin(stream, conference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,29 +280,38 @@ public class MucManager : StreamInteractionModule, Object {
|
||||||
private_room_occupant_updated(account, room, occupant);
|
private_room_occupant_updated(account, room, occupant);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
stream_interactor.module_manager.get_module(account, Xep.Bookmarks.Module.IDENTITY).received_conferences.connect( (stream, conferences) => {
|
|
||||||
|
bookmarks_provider[account] = stream_interactor.module_manager.get_module(account, Xep.Bookmarks.Module.IDENTITY);
|
||||||
|
|
||||||
|
bookmarks_provider[account].received_conferences.connect( (stream, conferences) => {
|
||||||
sync_autojoin_active(account, conferences);
|
sync_autojoin_active(account, conferences);
|
||||||
bookmarks_updated(account, conferences);
|
bookmarks_updated(account, conferences);
|
||||||
});
|
});
|
||||||
|
bookmarks_provider[account].conference_added.connect( (stream, conference) => {
|
||||||
|
sync_autojoin_state(account, conference.jid, conference);
|
||||||
|
conference_added(account, conference);
|
||||||
|
});
|
||||||
|
bookmarks_provider[account].conference_removed.connect( (stream, jid) => {
|
||||||
|
sync_autojoin_state(account, jid, null);
|
||||||
|
conference_removed(account, jid);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void on_stream_negotiated(Account account, XmppStream stream) {
|
private async void on_stream_negotiated(Account account, XmppStream stream) {
|
||||||
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
|
if (bookmarks_provider[account] == null) return;
|
||||||
if (conferences == null) {
|
|
||||||
join_all_active(account);
|
Set<Conference>? conferences = yield bookmarks_provider[account].get_conferences(stream);
|
||||||
} else {
|
|
||||||
foreach (Xep.Bookmarks.Conference bookmark in conferences) {
|
if (conferences == null) {
|
||||||
if (bookmark.autojoin) {
|
join_all_active(account);
|
||||||
join(account, bookmark.jid, bookmark.nick, bookmark.password);
|
} else {
|
||||||
}
|
sync_autojoin_active(account, conferences);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void on_room_entred(Account account, XmppStream stream, Jid jid, string nick) {
|
private void on_room_entred(Account account, XmppStream stream, Jid jid, string nick) {
|
||||||
enter_errors.unset(jid);
|
enter_errors.unset(jid);
|
||||||
set_autojoin(stream, jid, nick, null); // TODO password
|
set_autojoin(account, 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);
|
||||||
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(jid, account, Conversation.Type.GROUPCHAT);
|
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(jid, account, Conversation.Type.GROUPCHAT);
|
||||||
|
@ -315,65 +328,77 @@ 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, Set<Conference> conferences) {
|
||||||
Gee.List<Conversation> conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account);
|
Gee.List<Conversation> conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account);
|
||||||
leave_non_autojoin(account, conferences, conversations);
|
foreach (Conference conference in conferences) {
|
||||||
join_autojoin(account, conferences, conversations);
|
sync_autojoin_state(account, conference.jid, conference, 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) {
|
private void sync_autojoin_state(Account account, Jid jid, Conference? conference, Gee.List<Conversation>? conversations_ = null) {
|
||||||
foreach (Xep.Bookmarks.Conference conference in conferences) {
|
Gee.List<Conversation> conversations = conversations_ ?? stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account);
|
||||||
if (!conference.autojoin) continue;
|
|
||||||
|
if (conference != null && conference.autojoin) {
|
||||||
|
// Join if we should join
|
||||||
bool is_active = false;
|
bool is_active = false;
|
||||||
foreach (Conversation conversation in conversations) {
|
foreach (Conversation conversation in conversations) {
|
||||||
if (conference.jid.equals(conversation.counterpart)) is_active = true;
|
if (conference.jid.equals(conversation.counterpart)) is_active = true;
|
||||||
}
|
}
|
||||||
if (!is_active) {
|
if (!is_active || !is_joined(jid, account)) {
|
||||||
join(account, conference.jid, conference.nick, conference.password);
|
join(account, conference.jid, conference.nick, conference.password);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Leave if we should leave
|
||||||
|
bool is_active = false;
|
||||||
|
foreach (Conversation conversation in conversations) {
|
||||||
|
if (conversation.type_ != Conversation.Type.GROUPCHAT || !conversation.account.equals(account)) continue;
|
||||||
|
if (jid.equals(conversation.counterpart)) {
|
||||||
|
is_active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_active) {
|
||||||
|
part(account, jid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void set_autojoin(XmppStream stream, Jid jid, string? nick, string? password) {
|
private void set_autojoin(Account account, XmppStream stream, Jid jid, string? nick, string? password) {
|
||||||
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
|
bookmarks_provider[account].get_conferences.begin(stream, (_, res) => {
|
||||||
|
Set<Conference>? conferences = bookmarks_provider[account].get_conferences.end(res);
|
||||||
if (conferences == null) return;
|
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) {
|
Conference changed = new Xep.Bookmarks.Bookmarks1Conference(jid) { nick=nick, password=password, autojoin=true };
|
||||||
if (conference.jid.equals_bare(jid) && conference.nick == nick && conference.password == password) {
|
foreach (Conference conference in conferences) {
|
||||||
|
if (conference.jid.equals(jid)) {
|
||||||
if (!conference.autojoin) {
|
if (!conference.autojoin) {
|
||||||
conference.autojoin = true;
|
Conference new_conference = new Conference();
|
||||||
stream.get_module(Xep.Bookmarks.Module.IDENTITY).set_conferences(stream, conferences);
|
new_conference.jid = jid;
|
||||||
|
new_conference.autojoin = true;
|
||||||
|
new_conference.nick = nick;
|
||||||
|
new_conference.password = password;
|
||||||
|
bookmarks_provider[account].replace_conference.begin(stream, conference, new_conference);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream.get_module(Xep.Bookmarks.Module.IDENTITY).add_conference(stream, changed);
|
bookmarks_provider[account].add_conference.begin(stream, changed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unset_autojoin(XmppStream stream, Jid jid) {
|
private void unset_autojoin(Account account, XmppStream stream, Jid jid) {
|
||||||
stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
|
bookmarks_provider[account].get_conferences.begin(stream, (_, res) => {
|
||||||
|
Set<Conference>? conferences = bookmarks_provider[account].get_conferences.end(res);
|
||||||
if (conferences == null) return;
|
if (conferences == null) return;
|
||||||
foreach (Xep.Bookmarks.Conference conference in conferences) {
|
|
||||||
if (conference.jid.equals_bare(jid)) {
|
foreach (Conference conference in conferences) {
|
||||||
|
if (conference.jid.equals(jid)) {
|
||||||
if (conference.autojoin) {
|
if (conference.autojoin) {
|
||||||
conference.autojoin = false;
|
Conference new_conference = new Conference();
|
||||||
stream.get_module(Xep.Bookmarks.Module.IDENTITY).set_conferences(stream, conferences);
|
new_conference.jid = jid;
|
||||||
|
new_conference.autojoin = false;
|
||||||
|
new_conference.nick = conference.nick;
|
||||||
|
new_conference.password = conference.password;
|
||||||
|
bookmarks_provider[account].replace_conference.begin(stream, conference, new_conference);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ protected class AddGroupchatDialog : Gtk.Dialog {
|
||||||
[GtkChild] private Entry nick_entry;
|
[GtkChild] private Entry nick_entry;
|
||||||
|
|
||||||
private StreamInteractor stream_interactor;
|
private StreamInteractor stream_interactor;
|
||||||
private Xmpp.Xep.Bookmarks.Conference? edit_conference = null;
|
private Conference? edit_conference = null;
|
||||||
private bool alias_entry_changed = false;
|
private bool alias_entry_changed = false;
|
||||||
|
|
||||||
public AddGroupchatDialog(StreamInteractor stream_interactor) {
|
public AddGroupchatDialog(StreamInteractor stream_interactor) {
|
||||||
|
@ -36,7 +36,7 @@ protected class AddGroupchatDialog : Gtk.Dialog {
|
||||||
nick_entry.key_release_event.connect(check_ok);
|
nick_entry.key_release_event.connect(check_ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddGroupchatDialog.for_conference(StreamInteractor stream_interactor, Account account, Xmpp.Xep.Bookmarks.Conference conference) {
|
public AddGroupchatDialog.for_conference(StreamInteractor stream_interactor, Account account, Conference conference) {
|
||||||
this(stream_interactor);
|
this(stream_interactor);
|
||||||
edit_conference = conference;
|
edit_conference = conference;
|
||||||
ok_button.label = _("Save");
|
ok_button.label = _("Save");
|
||||||
|
@ -65,7 +65,8 @@ 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.parse(jid_entry.text));
|
Conference conference = new Conference();
|
||||||
|
conference.jid = 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) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ using Gee;
|
||||||
using Gtk;
|
using Gtk;
|
||||||
|
|
||||||
using Xmpp;
|
using Xmpp;
|
||||||
|
using Xmpp.Xep.Bookmarks;
|
||||||
using Dino.Entities;
|
using Dino.Entities;
|
||||||
|
|
||||||
namespace Dino.Ui {
|
namespace Dino.Ui {
|
||||||
|
@ -11,7 +12,8 @@ protected class ConferenceList : FilterableList {
|
||||||
public signal void conversation_selected(Conversation? conversation);
|
public signal void conversation_selected(Conversation? conversation);
|
||||||
|
|
||||||
private StreamInteractor stream_interactor;
|
private StreamInteractor stream_interactor;
|
||||||
private HashMap<Account, Gee.List<Xep.Bookmarks.Conference>> lists = new HashMap<Account, Gee.List<Xep.Bookmarks.Conference>>(Account.hash_func, Account.equals_func);
|
private HashMap<Account, Set<Conference>> lists = new HashMap<Account, Set<Conference>>(Account.hash_func, Account.equals_func);
|
||||||
|
private HashMap<Account, HashMap<Jid, Widget>> widgets = new HashMap<Account, HashMap<Jid, Widget>>(Account.hash_func, Account.equals_func);
|
||||||
|
|
||||||
public ConferenceList(StreamInteractor stream_interactor) {
|
public ConferenceList(StreamInteractor stream_interactor) {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
|
@ -26,20 +28,42 @@ protected class ConferenceList : FilterableList {
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach (Account account in stream_interactor.get_accounts()) {
|
foreach (Account account in stream_interactor.get_accounts()) {
|
||||||
stream_interactor.get_module(MucManager.IDENTITY).get_bookmarks(account, (stream, conferences) => { on_conference_bookmarks_received(stream, account, conferences); });
|
stream_interactor.get_module(MucManager.IDENTITY).get_bookmarks.begin(account, (_, res) => {
|
||||||
|
Set<Conference>? conferences = stream_interactor.get_module(MucManager.IDENTITY).get_bookmarks.end(res);
|
||||||
|
set_bookmarks(account, conferences);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_interactor.get_module(MucManager.IDENTITY).conference_added.connect(add_conference);
|
||||||
|
stream_interactor.get_module(MucManager.IDENTITY).conference_removed.connect(remove_conference);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void add_conference(Account account, Conference conference) {
|
||||||
|
if (!widgets.has_key(account)) {
|
||||||
|
widgets[account] = new HashMap<Jid, Widget>(Jid.hash_func, Jid.equals_func);
|
||||||
|
}
|
||||||
|
var widget = new ConferenceListRow(stream_interactor, conference, account);
|
||||||
|
widgets[account][conference.jid] = widget;
|
||||||
|
add(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void remove_conference(Account account, Jid jid) {
|
||||||
|
if (widgets.has_key(account) && widgets[account].has_key(jid)) {
|
||||||
|
widgets[account][jid].destroy();
|
||||||
|
widgets[account].unset(jid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh_conferences() {
|
public void refresh_conferences() {
|
||||||
@foreach((widget) => { remove(widget); });
|
@foreach((widget) => { remove(widget); });
|
||||||
foreach (Account account in lists.keys) {
|
foreach (Account account in lists.keys) {
|
||||||
foreach (Xep.Bookmarks.Conference conference in lists[account]) {
|
foreach (Conference conference in lists[account]) {
|
||||||
add(new ConferenceListRow(stream_interactor, conference, account));
|
add_conference(account, conference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void on_conference_bookmarks_received(XmppStream stream, Account account, Gee.List<Xep.Bookmarks.Conference>? conferences) {
|
private void set_bookmarks(Account account, Set<Conference>? conferences) {
|
||||||
if (conferences == null) {
|
if (conferences == null) {
|
||||||
lists.unset(account);
|
lists.unset(account);
|
||||||
} else {
|
} else {
|
||||||
|
@ -78,9 +102,9 @@ protected class ConferenceList : FilterableList {
|
||||||
|
|
||||||
internal class ConferenceListRow : ListRow {
|
internal class ConferenceListRow : ListRow {
|
||||||
|
|
||||||
public Xep.Bookmarks.Conference bookmark;
|
public Conference bookmark;
|
||||||
|
|
||||||
public ConferenceListRow(StreamInteractor stream_interactor, Xep.Bookmarks.Conference bookmark, Account account) {
|
public ConferenceListRow(StreamInteractor stream_interactor, Conference bookmark, Account account) {
|
||||||
this.jid = bookmark.jid;
|
this.jid = bookmark.jid;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.bookmark = bookmark;
|
this.bookmark = bookmark;
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class StreamModule : XmppStreamModule {
|
||||||
if (!am_on_devicelist) {
|
if (!am_on_devicelist) {
|
||||||
debug("Not on device list, adding id");
|
debug("Not on device list, adding id");
|
||||||
node.put_node(new StanzaNode.build("device", NS_URI).put_attribute("id", store.local_registration_id.to_string()));
|
node.put_node(new StanzaNode.build("device", NS_URI).put_attribute("id", store.local_registration_id.to_string()));
|
||||||
stream.get_module(Pubsub.Module.IDENTITY).publish(stream, jid, NODE_DEVICELIST, id, node, Xmpp.Xep.Pubsub.ACCESS_MODEL_OPEN);
|
stream.get_module(Pubsub.Module.IDENTITY).publish.begin(stream, jid, NODE_DEVICELIST, id, node, Xmpp.Xep.Pubsub.ACCESS_MODEL_OPEN);
|
||||||
}
|
}
|
||||||
publish_bundles_if_needed(stream, jid);
|
publish_bundles_if_needed(stream, jid);
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ public class StreamModule : XmppStreamModule {
|
||||||
}
|
}
|
||||||
bundle.put_node(prekeys);
|
bundle.put_node(prekeys);
|
||||||
|
|
||||||
stream.get_module(Pubsub.Module.IDENTITY).publish(stream, null, @"$NODE_BUNDLES:$device_id", "1", bundle, Xmpp.Xep.Pubsub.ACCESS_MODEL_OPEN);
|
stream.get_module(Pubsub.Module.IDENTITY).publish.begin(stream, null, @"$NODE_BUNDLES:$device_id", "1", bundle, Xmpp.Xep.Pubsub.ACCESS_MODEL_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string get_ns() {
|
public override string get_ns() {
|
||||||
|
|
|
@ -19,6 +19,8 @@ SOURCES
|
||||||
"src/core/xmpp_stream.vala"
|
"src/core/xmpp_stream.vala"
|
||||||
|
|
||||||
"src/module/bind.vala"
|
"src/module/bind.vala"
|
||||||
|
"src/module/bookmarks_provider.vala"
|
||||||
|
"src/module/conference.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/jid.vala"
|
||||||
|
@ -39,6 +41,9 @@ SOURCES
|
||||||
"src/module/tls.vala"
|
"src/module/tls.vala"
|
||||||
"src/module/util.vala"
|
"src/module/util.vala"
|
||||||
|
|
||||||
|
"src/module/xep/0048_bookmarks.vala"
|
||||||
|
"src/module/xep/0048_conference.vala"
|
||||||
|
"src/module/xep/0402_bookmarks2.vala"
|
||||||
"src/module/xep/0004_data_forms.vala"
|
"src/module/xep/0004_data_forms.vala"
|
||||||
"src/module/xep/0030_service_discovery/flag.vala"
|
"src/module/xep/0030_service_discovery/flag.vala"
|
||||||
"src/module/xep/0030_service_discovery/identity.vala"
|
"src/module/xep/0030_service_discovery/identity.vala"
|
||||||
|
@ -50,8 +55,6 @@ SOURCES
|
||||||
"src/module/xep/0045_muc/module.vala"
|
"src/module/xep/0045_muc/module.vala"
|
||||||
"src/module/xep/0045_muc/status_code.vala"
|
"src/module/xep/0045_muc/status_code.vala"
|
||||||
"src/module/xep/0047_in_band_bytestreams.vala"
|
"src/module/xep/0047_in_band_bytestreams.vala"
|
||||||
"src/module/xep/0048_bookmarks/conference.vala"
|
|
||||||
"src/module/xep/0048_bookmarks/module.vala"
|
|
||||||
"src/module/xep/0049_private_xml_storage.vala"
|
"src/module/xep/0049_private_xml_storage.vala"
|
||||||
"src/module/xep/0054_vcard/module.vala"
|
"src/module/xep/0054_vcard/module.vala"
|
||||||
"src/module/xep/0060_pubsub.vala"
|
"src/module/xep/0060_pubsub.vala"
|
||||||
|
|
17
xmpp-vala/src/module/bookmarks_provider.vala
Normal file
17
xmpp-vala/src/module/bookmarks_provider.vala
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using Gee;
|
||||||
|
|
||||||
|
namespace Xmpp {
|
||||||
|
|
||||||
|
public interface BookmarksProvider : Object {
|
||||||
|
public signal void conference_added(XmppStream stream, Conference conferences);
|
||||||
|
public signal void conference_removed(XmppStream stream, Jid jid);
|
||||||
|
public signal void conference_changed(XmppStream stream, Conference conferences);
|
||||||
|
public signal void received_conferences(XmppStream stream, Set<Conference> conferences);
|
||||||
|
|
||||||
|
public async abstract async Set<Conference>? get_conferences(XmppStream stream);
|
||||||
|
public async abstract void add_conference(XmppStream stream, Conference conference);
|
||||||
|
public async abstract void remove_conference(XmppStream stream, Conference conference);
|
||||||
|
public async abstract void replace_conference(XmppStream stream, Conference orig_conference, Conference modified_conference);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
xmpp-vala/src/module/conference.vala
Normal file
19
xmpp-vala/src/module/conference.vala
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
namespace Xmpp {
|
||||||
|
|
||||||
|
public class Conference : Object {
|
||||||
|
public virtual Jid jid { get; set; }
|
||||||
|
public virtual bool autojoin { get; set; }
|
||||||
|
public virtual string? nick { get; set; }
|
||||||
|
public virtual string? name { get; set; }
|
||||||
|
public virtual string? password { get; set; }
|
||||||
|
|
||||||
|
public static bool equal_func(Conference a, Conference b) {
|
||||||
|
return a.jid.equals(b.jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint hash_func(Conference a) {
|
||||||
|
return Jid.hash_func(a.jid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
80
xmpp-vala/src/module/xep/0048_bookmarks.vala
Normal file
80
xmpp-vala/src/module/xep/0048_bookmarks.vala
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
using Gee;
|
||||||
|
|
||||||
|
namespace Xmpp.Xep.Bookmarks {
|
||||||
|
private const string NS_URI = "storage:bookmarks";
|
||||||
|
|
||||||
|
public class Module : BookmarksProvider, XmppStreamModule {
|
||||||
|
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0048_bookmarks_module");
|
||||||
|
|
||||||
|
public async Set<Conference>? get_conferences(XmppStream stream) {
|
||||||
|
Set<Conference> ret = new HashSet<Conference>(Conference.hash_func, Conference.equal_func);
|
||||||
|
|
||||||
|
StanzaNode get_node = new StanzaNode.build("storage", NS_URI).add_self_xmlns();
|
||||||
|
stream.get_module(PrivateXmlStorage.Module.IDENTITY).retrieve(stream, get_node, (stream, node) => {
|
||||||
|
if (node != null) {
|
||||||
|
Gee.List<StanzaNode> conferences_node = node.get_subnode("storage", NS_URI).get_subnodes("conference", NS_URI);
|
||||||
|
foreach (StanzaNode conference_node in conferences_node) {
|
||||||
|
Conference? conference = Bookmarks1Conference.create_from_stanza_node(conference_node);
|
||||||
|
ret.add(conference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Idle.add(get_conferences.callback);
|
||||||
|
});
|
||||||
|
yield;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void set_conferences(XmppStream stream, Set<Conference> conferences) {
|
||||||
|
StanzaNode storage_node = (new StanzaNode.build("storage", NS_URI)).add_self_xmlns();
|
||||||
|
foreach (Conference conference in conferences) {
|
||||||
|
Bookmarks1Conference? bookmarks1conference = conference as Bookmarks1Conference;
|
||||||
|
if (bookmarks1conference != null) {
|
||||||
|
storage_node.put_node(bookmarks1conference.stanza_node);
|
||||||
|
} else {
|
||||||
|
StanzaNode conference_node = new StanzaNode.build("conference", NS_URI)
|
||||||
|
.put_attribute("jid", conference.jid.to_string())
|
||||||
|
.put_attribute("autojoin", conference.autojoin ? "true" : "false");
|
||||||
|
if (conference.name != null) {
|
||||||
|
conference_node.put_attribute("name", conference.name);
|
||||||
|
}
|
||||||
|
if (conference.nick != null) {
|
||||||
|
conference_node.put_node(new StanzaNode.build("nick", NS_URI)
|
||||||
|
.put_node(new StanzaNode.text(conference.nick)));
|
||||||
|
}
|
||||||
|
storage_node.put_node(conference_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.get_module(PrivateXmlStorage.Module.IDENTITY).store(stream, storage_node, (stream) => {
|
||||||
|
stream.get_module(Module.IDENTITY).received_conferences(stream, conferences);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void add_conference(XmppStream stream, Conference conference) {
|
||||||
|
Set<Conference>? conferences = yield get_conferences(stream);
|
||||||
|
conferences.add(conference);
|
||||||
|
stream.get_module(Module.IDENTITY).set_conferences(stream, conferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void replace_conference(XmppStream stream, Conference orig_conference, Conference modified_conference) {
|
||||||
|
Set<Conference>? conferences = yield get_conferences(stream);
|
||||||
|
conferences.remove(orig_conference);
|
||||||
|
conferences.add(modified_conference);
|
||||||
|
stream.get_module(Module.IDENTITY).set_conferences(stream, conferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void remove_conference(XmppStream stream, Conference conference_remove) {
|
||||||
|
Set<Conference>? conferences = yield get_conferences(stream);
|
||||||
|
conferences.remove(conference_remove);
|
||||||
|
stream.get_module(Module.IDENTITY).set_conferences(stream, conferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void attach(XmppStream stream) { }
|
||||||
|
|
||||||
|
public override void detach(XmppStream stream) { }
|
||||||
|
|
||||||
|
public override string get_ns() { return NS_URI; }
|
||||||
|
public override string get_id() { return IDENTITY.id; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,92 +0,0 @@
|
||||||
namespace Xmpp.Xep.Bookmarks {
|
|
||||||
|
|
||||||
public class Conference : Object {
|
|
||||||
|
|
||||||
public const string ATTRIBUTE_AUTOJOIN = "autojoin";
|
|
||||||
public const string ATTRIBUTE_JID = "jid";
|
|
||||||
public const string ATTRIBUTE_NAME = "name";
|
|
||||||
|
|
||||||
public const string NODE_NICK = "nick";
|
|
||||||
public const string NODE_PASSWORD = "password";
|
|
||||||
|
|
||||||
public StanzaNode stanza_node;
|
|
||||||
|
|
||||||
public bool autojoin {
|
|
||||||
get {
|
|
||||||
string? attr = stanza_node.get_attribute(ATTRIBUTE_AUTOJOIN);
|
|
||||||
return attr == "true" || attr == "1";
|
|
||||||
}
|
|
||||||
set { stanza_node.set_attribute(ATTRIBUTE_AUTOJOIN, value.to_string()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private Jid jid_;
|
|
||||||
public Jid jid {
|
|
||||||
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 {
|
|
||||||
get { return stanza_node.get_attribute(ATTRIBUTE_NAME); }
|
|
||||||
set {
|
|
||||||
if (value == null) return; // TODO actually remove
|
|
||||||
stanza_node.set_attribute(ATTRIBUTE_NAME, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? nick {
|
|
||||||
get {
|
|
||||||
StanzaNode? nick_node = stanza_node.get_subnode(NODE_NICK);
|
|
||||||
return nick_node == null ? null : nick_node.get_string_content();
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
StanzaNode? nick_node = stanza_node.get_subnode(NODE_NICK);
|
|
||||||
if (value == null) {
|
|
||||||
if (nick_node != null) stanza_node.sub_nodes.remove(nick_node);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (nick_node == null) {
|
|
||||||
nick_node = new StanzaNode.build(NODE_NICK, NS_URI);
|
|
||||||
stanza_node.put_node(nick_node);
|
|
||||||
}
|
|
||||||
nick_node.sub_nodes.clear();
|
|
||||||
nick_node.put_node(new StanzaNode.text(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? password {
|
|
||||||
get {
|
|
||||||
StanzaNode? password_node = stanza_node.get_subnode(NODE_PASSWORD);
|
|
||||||
return password_node == null ? null : password_node.get_string_content();
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
StanzaNode? password_node = stanza_node.get_subnode(NODE_PASSWORD);
|
|
||||||
if (value == null) {
|
|
||||||
if (password_node != null) stanza_node.sub_nodes.remove(password_node);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (password_node == null) {
|
|
||||||
password_node = new StanzaNode.build(NODE_PASSWORD);
|
|
||||||
stanza_node.put_node(password_node);
|
|
||||||
}
|
|
||||||
password_node.put_node(new StanzaNode.text(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Conference(Jid jid) {
|
|
||||||
this.stanza_node = new StanzaNode.build("conference", NS_URI);
|
|
||||||
this.jid = jid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Conference? create_from_stanza_node(StanzaNode stanza_node) {
|
|
||||||
if (stanza_node.get_attribute(ATTRIBUTE_JID) != null) {
|
|
||||||
return new Conference.from_stanza_node(stanza_node);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Conference.from_stanza_node(StanzaNode stanza_node) {
|
|
||||||
this.stanza_node = stanza_node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
using Gee;
|
|
||||||
|
|
||||||
namespace Xmpp.Xep.Bookmarks {
|
|
||||||
private const string NS_URI = "storage:bookmarks";
|
|
||||||
|
|
||||||
public class Module : XmppStreamModule {
|
|
||||||
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0048_bookmarks_module");
|
|
||||||
|
|
||||||
public signal void received_conferences(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) {
|
|
||||||
StanzaNode get_node = new StanzaNode.build("storage", NS_URI).add_self_xmlns();
|
|
||||||
stream.get_module(PrivateXmlStorage.Module.IDENTITY).retrieve(stream, get_node, (stream, node) => {
|
|
||||||
if (node == null) {
|
|
||||||
listener(stream, null);
|
|
||||||
} else {
|
|
||||||
Gee.List<Conference> conferences = get_conferences_from_stanza(node);
|
|
||||||
listener(stream, conferences);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set_conferences(XmppStream stream, Gee.List<Conference> conferences) {
|
|
||||||
StanzaNode storage_node = (new StanzaNode.build("storage", NS_URI)).add_self_xmlns();
|
|
||||||
foreach (Conference conference in conferences) {
|
|
||||||
storage_node.put_node(conference.stanza_node);
|
|
||||||
}
|
|
||||||
stream.get_module(PrivateXmlStorage.Module.IDENTITY).store(stream, storage_node, (stream) => {
|
|
||||||
stream.get_module(Module.IDENTITY).received_conferences(stream, conferences);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add_conference(XmppStream stream, Conference conference) {
|
|
||||||
get_conferences(stream, (stream, conferences) => {
|
|
||||||
conferences.add(conference);
|
|
||||||
stream.get_module(Module.IDENTITY).set_conferences(stream, conferences);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replace_conference(XmppStream stream, Conference orig_conference, Conference modified_conference) {
|
|
||||||
get_conferences(stream, (stream, conferences) => {
|
|
||||||
foreach (Conference conference in conferences) {
|
|
||||||
if (conference.autojoin == orig_conference.autojoin && conference.jid.equals(orig_conference.jid) &&
|
|
||||||
conference.name == orig_conference.name && conference.nick == orig_conference.nick) {
|
|
||||||
conference.autojoin = modified_conference.autojoin;
|
|
||||||
conference.jid = modified_conference.jid;
|
|
||||||
conference.name = modified_conference.name;
|
|
||||||
conference.nick = modified_conference.nick;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.get_module(Module.IDENTITY).set_conferences(stream, conferences);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove_conference(XmppStream stream, Conference conference_remove) {
|
|
||||||
get_conferences(stream, (stream, conferences) => {
|
|
||||||
Conference? rem = null;
|
|
||||||
foreach (Conference conference in conferences) {
|
|
||||||
if (conference.name == conference_remove.name && conference.jid.equals(conference_remove.jid) && conference.autojoin == conference_remove.autojoin) {
|
|
||||||
rem = conference;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rem != null) conferences.remove(rem);
|
|
||||||
stream.get_module(Module.IDENTITY).set_conferences(stream, conferences);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void attach(XmppStream stream) { }
|
|
||||||
|
|
||||||
public override void detach(XmppStream stream) { }
|
|
||||||
|
|
||||||
public override string get_ns() { return NS_URI; }
|
|
||||||
public override string get_id() { return IDENTITY.id; }
|
|
||||||
|
|
||||||
private static Gee.List<Conference> get_conferences_from_stanza(StanzaNode node) {
|
|
||||||
Gee.List<Conference> conferences = new ArrayList<Conference>();
|
|
||||||
Gee.List<StanzaNode> conferenceNodes = node.get_subnode("storage", NS_URI).get_subnodes("conference", NS_URI);
|
|
||||||
foreach (StanzaNode conferenceNode in conferenceNodes) {
|
|
||||||
Conference? conference = Conference.create_from_stanza_node(conferenceNode);
|
|
||||||
conferences.add(conference);
|
|
||||||
}
|
|
||||||
return conferences;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
92
xmpp-vala/src/module/xep/0048_conference.vala
Normal file
92
xmpp-vala/src/module/xep/0048_conference.vala
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
namespace Xmpp.Xep.Bookmarks {
|
||||||
|
|
||||||
|
public class Bookmarks1Conference : Conference {
|
||||||
|
|
||||||
|
public const string ATTRIBUTE_AUTOJOIN = "autojoin";
|
||||||
|
public const string ATTRIBUTE_JID = "jid";
|
||||||
|
public const string ATTRIBUTE_NAME = "name";
|
||||||
|
|
||||||
|
public const string NODE_NICK = "nick";
|
||||||
|
public const string NODE_PASSWORD = "password";
|
||||||
|
|
||||||
|
public StanzaNode stanza_node;
|
||||||
|
|
||||||
|
public override bool autojoin {
|
||||||
|
get {
|
||||||
|
string? attr = stanza_node.get_attribute(ATTRIBUTE_AUTOJOIN);
|
||||||
|
return attr == "true" || attr == "1";
|
||||||
|
}
|
||||||
|
set { stanza_node.set_attribute(ATTRIBUTE_AUTOJOIN, value.to_string()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jid jid_;
|
||||||
|
public override Jid jid {
|
||||||
|
get { return jid_ ?? (jid_ = Jid.parse(stanza_node.get_attribute(ATTRIBUTE_JID))); }
|
||||||
|
set { stanza_node.set_attribute(ATTRIBUTE_JID, value.to_string()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string? name {
|
||||||
|
get { return stanza_node.get_attribute(ATTRIBUTE_NAME); }
|
||||||
|
set {
|
||||||
|
if (value == null) return; // TODO actually remove
|
||||||
|
stanza_node.set_attribute(ATTRIBUTE_NAME, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string? nick {
|
||||||
|
get {
|
||||||
|
StanzaNode? nick_node = stanza_node.get_subnode(NODE_NICK);
|
||||||
|
return nick_node == null ? null : nick_node.get_string_content();
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
StanzaNode? nick_node = stanza_node.get_subnode(NODE_NICK);
|
||||||
|
if (value == null) {
|
||||||
|
if (nick_node != null) stanza_node.sub_nodes.remove(nick_node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (nick_node == null) {
|
||||||
|
nick_node = new StanzaNode.build(NODE_NICK, NS_URI);
|
||||||
|
stanza_node.put_node(nick_node);
|
||||||
|
}
|
||||||
|
nick_node.sub_nodes.clear();
|
||||||
|
nick_node.put_node(new StanzaNode.text(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string? password {
|
||||||
|
get {
|
||||||
|
StanzaNode? password_node = stanza_node.get_subnode(NODE_PASSWORD);
|
||||||
|
return password_node == null ? null : password_node.get_string_content();
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
StanzaNode? password_node = stanza_node.get_subnode(NODE_PASSWORD);
|
||||||
|
if (value == null) {
|
||||||
|
if (password_node != null) stanza_node.sub_nodes.remove(password_node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (password_node == null) {
|
||||||
|
password_node = new StanzaNode.build(NODE_PASSWORD);
|
||||||
|
stanza_node.put_node(password_node);
|
||||||
|
}
|
||||||
|
password_node.put_node(new StanzaNode.text(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bookmarks1Conference(Jid jid) {
|
||||||
|
this.stanza_node = new StanzaNode.build("conference", NS_URI);
|
||||||
|
this.jid = jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Conference? create_from_stanza_node(StanzaNode stanza_node) {
|
||||||
|
if (stanza_node.get_attribute(ATTRIBUTE_JID) != null) {
|
||||||
|
return new Bookmarks1Conference.from_stanza_node(stanza_node);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bookmarks1Conference.from_stanza_node(StanzaNode stanza_node) {
|
||||||
|
this.stanza_node = stanza_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,24 @@ namespace Xmpp.Xep.Pubsub {
|
||||||
event_listeners[node] = new EventListenerDelegate((owned)listener);
|
event_listeners[node] = new EventListenerDelegate((owned)listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Gee.List<StanzaNode>? request_all(XmppStream stream, Jid jid, string node) { // TODO multiple nodes gehen auch
|
||||||
|
Iq.Stanza request_iq = new Iq.Stanza.get(new StanzaNode.build("pubsub", NS_URI).add_self_xmlns().put_node(new StanzaNode.build("items", NS_URI).put_attribute("node", node)));
|
||||||
|
request_iq.to = jid;
|
||||||
|
|
||||||
|
Gee.List<StanzaNode>? ret = null;
|
||||||
|
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, request_iq, (stream, iq) => {
|
||||||
|
StanzaNode event_node = iq.stanza.get_subnode("pubsub", NS_URI);
|
||||||
|
if (event_node == null) return;
|
||||||
|
StanzaNode items_node = event_node.get_subnode("items", NS_URI);
|
||||||
|
if (items_node == null) return;
|
||||||
|
ret = items_node.get_subnodes("item", NS_URI);
|
||||||
|
Idle.add(request_all.callback);
|
||||||
|
});
|
||||||
|
yield;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
public delegate void OnResult(XmppStream stream, Jid jid, string? id, StanzaNode? node);
|
public delegate void OnResult(XmppStream stream, Jid jid, string? id, StanzaNode? node);
|
||||||
public void request(XmppStream stream, Jid jid, string node, owned OnResult listener) { // TODO multiple nodes gehen auch
|
public void request(XmppStream stream, Jid jid, string node, owned OnResult listener) { // TODO multiple nodes gehen auch
|
||||||
Iq.Stanza request_iq = new Iq.Stanza.get(new StanzaNode.build("pubsub", NS_URI).add_self_xmlns().put_node(new StanzaNode.build("items", NS_URI).put_attribute("node", node)));
|
Iq.Stanza request_iq = new Iq.Stanza.get(new StanzaNode.build("pubsub", NS_URI).add_self_xmlns().put_node(new StanzaNode.build("items", NS_URI).put_attribute("node", node)));
|
||||||
|
@ -34,7 +52,7 @@ namespace Xmpp.Xep.Pubsub {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publish(XmppStream stream, Jid? jid, string node_id, string? item_id, StanzaNode content, string? access_model=null) {
|
public async bool publish(XmppStream stream, Jid? jid, string node_id, string? item_id, StanzaNode content, string? access_model=null, int? max_items = null) {
|
||||||
StanzaNode pubsub_node = new StanzaNode.build("pubsub", NS_URI).add_self_xmlns();
|
StanzaNode pubsub_node = new StanzaNode.build("pubsub", NS_URI).add_self_xmlns();
|
||||||
StanzaNode publish_node = new StanzaNode.build("publish", NS_URI).put_attribute("node", node_id);
|
StanzaNode publish_node = new StanzaNode.build("publish", NS_URI).put_attribute("node", node_id);
|
||||||
pubsub_node.put_node(publish_node);
|
pubsub_node.put_node(publish_node);
|
||||||
|
@ -43,7 +61,7 @@ namespace Xmpp.Xep.Pubsub {
|
||||||
items_node.put_node(content);
|
items_node.put_node(content);
|
||||||
publish_node.put_node(items_node);
|
publish_node.put_node(items_node);
|
||||||
|
|
||||||
if (access_model != null) {
|
if (access_model != null || max_items != null) {
|
||||||
StanzaNode publish_options_node = new StanzaNode.build("publish-options", NS_URI);
|
StanzaNode publish_options_node = new StanzaNode.build("publish-options", NS_URI);
|
||||||
pubsub_node.put_node(publish_options_node);
|
pubsub_node.put_node(publish_options_node);
|
||||||
|
|
||||||
|
@ -51,14 +69,44 @@ namespace Xmpp.Xep.Pubsub {
|
||||||
DataForms.DataForm.HiddenField form_type_field = new DataForms.DataForm.HiddenField() { var="FORM_TYPE" };
|
DataForms.DataForm.HiddenField form_type_field = new DataForms.DataForm.HiddenField() { var="FORM_TYPE" };
|
||||||
form_type_field.set_value_string(NS_URI + "#publish-options");
|
form_type_field.set_value_string(NS_URI + "#publish-options");
|
||||||
data_form.add_field(form_type_field);
|
data_form.add_field(form_type_field);
|
||||||
DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="pubsub#access_model" };
|
if (access_model != null) {
|
||||||
field.set_value_string(access_model);
|
DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="pubsub#access_model" };
|
||||||
data_form.add_field(field);
|
field.set_value_string(access_model);
|
||||||
|
data_form.add_field(field);
|
||||||
|
}
|
||||||
|
if (max_items != null) {
|
||||||
|
DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="pubsub#max_items" };
|
||||||
|
field.set_value_string(max_items.to_string());
|
||||||
|
data_form.add_field(field);
|
||||||
|
}
|
||||||
publish_options_node.put_node(data_form.get_submit_node());
|
publish_options_node.put_node(data_form.get_submit_node());
|
||||||
}
|
}
|
||||||
|
|
||||||
Iq.Stanza iq = new Iq.Stanza.set(pubsub_node);
|
Iq.Stanza iq = new Iq.Stanza.set(pubsub_node);
|
||||||
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, null);
|
bool ok = true;
|
||||||
|
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, result_iq) => {
|
||||||
|
ok = !result_iq.is_error();
|
||||||
|
Idle.add(publish.callback);
|
||||||
|
});
|
||||||
|
yield;
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async bool retract_item(XmppStream stream, Jid? jid, string node_id, string item_id) {
|
||||||
|
StanzaNode pubsub_node = new StanzaNode.build("pubsub", NS_URI).add_self_xmlns()
|
||||||
|
.put_node(new StanzaNode.build("retract", NS_URI).put_attribute("node", node_id).put_attribute("notify", "true")
|
||||||
|
.put_node(new StanzaNode.build("item", NS_URI).put_attribute("id", item_id)));
|
||||||
|
|
||||||
|
Iq.Stanza iq = new Iq.Stanza.set(pubsub_node);
|
||||||
|
bool ok = true;
|
||||||
|
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, result_iq) => {
|
||||||
|
ok = !result_iq.is_error();
|
||||||
|
Idle.add(retract_item.callback);
|
||||||
|
});
|
||||||
|
yield;
|
||||||
|
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete_node(XmppStream stream, Jid? jid, string node_id) {
|
public void delete_node(XmppStream stream, Jid? jid, string node_id) {
|
||||||
|
@ -82,14 +130,30 @@ namespace Xmpp.Xep.Pubsub {
|
||||||
public override string get_id() { return IDENTITY.id; }
|
public override string get_id() { return IDENTITY.id; }
|
||||||
|
|
||||||
private void on_received_message(XmppStream stream, MessageStanza message) {
|
private void on_received_message(XmppStream stream, MessageStanza message) {
|
||||||
StanzaNode event_node = message.stanza.get_subnode("event", NS_URI_EVENT); if (event_node == null) return;
|
StanzaNode event_node = message.stanza.get_subnode("event", NS_URI_EVENT);
|
||||||
StanzaNode items_node = event_node.get_subnode("items", NS_URI_EVENT); if (items_node == null) return;
|
if (event_node == null) return;
|
||||||
StanzaNode item_node = items_node.get_subnode("item", NS_URI_EVENT); if (item_node == null) return;
|
StanzaNode items_node = event_node.get_subnode("items", NS_URI_EVENT);
|
||||||
|
if (items_node == null) return;
|
||||||
string node = items_node.get_attribute("node", NS_URI_EVENT);
|
string node = items_node.get_attribute("node", NS_URI_EVENT);
|
||||||
string id = item_node.get_attribute("id", NS_URI_EVENT);
|
|
||||||
if (event_listeners.has_key(node)) {
|
StanzaNode? item_node = items_node.get_subnode("item", NS_URI_EVENT);
|
||||||
event_listeners[node].on_result(stream, message.from, id, item_node.sub_nodes[0]);
|
if (item_node != null) {
|
||||||
|
string id = item_node.get_attribute("id", NS_URI_EVENT);
|
||||||
|
|
||||||
|
if (event_listeners.has_key(node)) {
|
||||||
|
event_listeners[node].on_result(stream, message.from, id, item_node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StanzaNode? retract_node = items_node.get_subnode("retract", NS_URI_EVENT);
|
||||||
|
if (retract_node != null) {
|
||||||
|
string id = retract_node.get_attribute("id", NS_URI_EVENT);
|
||||||
|
|
||||||
|
if (event_listeners.has_key(node)) {
|
||||||
|
event_listeners[node].on_result(stream, message.from, id, retract_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Xmpp.Xep.UserAvatars {
|
||||||
string sha1 = Checksum.compute_for_data(ChecksumType.SHA1, image);
|
string sha1 = Checksum.compute_for_data(ChecksumType.SHA1, image);
|
||||||
StanzaNode data_node = new StanzaNode.build("data", NS_URI_DATA).add_self_xmlns()
|
StanzaNode data_node = new StanzaNode.build("data", NS_URI_DATA).add_self_xmlns()
|
||||||
.put_node(new StanzaNode.text(Base64.encode(image)));
|
.put_node(new StanzaNode.text(Base64.encode(image)));
|
||||||
stream.get_module(Pubsub.Module.IDENTITY).publish(stream, null, NS_URI_DATA, sha1, data_node);
|
stream.get_module(Pubsub.Module.IDENTITY).publish.begin(stream, null, NS_URI_DATA, sha1, data_node);
|
||||||
|
|
||||||
StanzaNode metadata_node = new StanzaNode.build("metadata", NS_URI_METADATA).add_self_xmlns();
|
StanzaNode metadata_node = new StanzaNode.build("metadata", NS_URI_METADATA).add_self_xmlns();
|
||||||
StanzaNode info_node = new StanzaNode.build("info", NS_URI_METADATA)
|
StanzaNode info_node = new StanzaNode.build("info", NS_URI_METADATA)
|
||||||
|
@ -28,7 +28,7 @@ namespace Xmpp.Xep.UserAvatars {
|
||||||
.put_attribute("height", height.to_string())
|
.put_attribute("height", height.to_string())
|
||||||
.put_attribute("type", "image/png");
|
.put_attribute("type", "image/png");
|
||||||
metadata_node.put_node(info_node);
|
metadata_node.put_node(info_node);
|
||||||
stream.get_module(Pubsub.Module.IDENTITY).publish(stream, null, NS_URI_METADATA, sha1, metadata_node);
|
stream.get_module(Pubsub.Module.IDENTITY).publish.begin(stream, null, NS_URI_METADATA, sha1, metadata_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void attach(XmppStream stream) {
|
public override void attach(XmppStream stream) {
|
||||||
|
|
116
xmpp-vala/src/module/xep/0402_bookmarks2.vala
Normal file
116
xmpp-vala/src/module/xep/0402_bookmarks2.vala
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
using Gee;
|
||||||
|
|
||||||
|
namespace Xmpp.Xep.Bookmarks2 {
|
||||||
|
|
||||||
|
private const string NS_URI = "urn:xmpp:bookmarks:0";
|
||||||
|
|
||||||
|
public class Module : BookmarksProvider, XmppStreamModule {
|
||||||
|
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0402_bookmarks2");
|
||||||
|
|
||||||
|
public async Set<Conference>? get_conferences(XmppStream stream) {
|
||||||
|
HashMap<Jid, Conference>? hm = null;
|
||||||
|
|
||||||
|
Flag? flag = stream.get_flag(Flag.IDENTITY);
|
||||||
|
if (flag != null) {
|
||||||
|
hm = flag.conferences;
|
||||||
|
} else {
|
||||||
|
Gee.List<StanzaNode>? items = yield stream.get_module(Pubsub.Module.IDENTITY).request_all(stream, stream.get_flag(Bind.Flag.IDENTITY).my_jid.bare_jid, NS_URI);
|
||||||
|
|
||||||
|
hm = new HashMap<Jid, Conference>(Jid.hash_func, Jid.equals_func);
|
||||||
|
foreach (StanzaNode item_node in items) {
|
||||||
|
Conference? conference = parse_item_node(item_node, item_node.get_attribute("id"));
|
||||||
|
if (conference == null) continue;
|
||||||
|
hm[conference.jid] = conference;
|
||||||
|
}
|
||||||
|
stream.add_flag(new Flag(hm));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var ret = new HashSet<Conference>();
|
||||||
|
foreach (var conference in hm.values) {
|
||||||
|
ret.add(conference);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void add_conference(XmppStream stream, Conference conference) {
|
||||||
|
StanzaNode conference_node = new StanzaNode.build("conference", NS_URI).add_self_xmlns()
|
||||||
|
.put_attribute("autojoin", conference.autojoin ? "true" : "false");
|
||||||
|
if (conference.name != null) {
|
||||||
|
conference_node.put_attribute("name", conference.name);
|
||||||
|
}
|
||||||
|
if (conference.nick != null) {
|
||||||
|
conference_node.put_node((new StanzaNode.build("nick", NS_URI)).put_node(new StanzaNode.text(conference.nick)));
|
||||||
|
}
|
||||||
|
yield stream.get_module(Pubsub.Module.IDENTITY).publish(stream, stream.get_flag(Bind.Flag.IDENTITY).my_jid.bare_jid, NS_URI, conference.jid.to_string(), conference_node, Xmpp.Xep.Pubsub.ACCESS_MODEL_WHITELIST, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void replace_conference(XmppStream stream, Conference orig_conference, Conference modified_conference) {
|
||||||
|
yield add_conference(stream, modified_conference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void remove_conference(XmppStream stream, Conference conference) {
|
||||||
|
yield stream.get_module(Pubsub.Module.IDENTITY).retract_item(stream,
|
||||||
|
stream.get_flag(Bind.Flag.IDENTITY).my_jid.bare_jid,
|
||||||
|
NS_URI,
|
||||||
|
conference.jid.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void on_pupsub_event(XmppStream stream, Jid jid, string id, StanzaNode? node) {
|
||||||
|
if (node.name == "item") {
|
||||||
|
Conference conference = parse_item_node(node, id);
|
||||||
|
Flag? flag = stream.get_flag(Flag.IDENTITY);
|
||||||
|
if (flag != null) {
|
||||||
|
flag.conferences[conference.jid] = conference;
|
||||||
|
}
|
||||||
|
conference_added(stream, conference);
|
||||||
|
} else if (node.name == "retract") {
|
||||||
|
string jid_str = node.get_attribute("id");
|
||||||
|
Jid jid_parsed = Jid.parse(jid_str);
|
||||||
|
Flag? flag = stream.get_flag(Flag.IDENTITY);
|
||||||
|
if (flag != null) {
|
||||||
|
flag.conferences.unset(jid_parsed);
|
||||||
|
}
|
||||||
|
conference_removed(stream, jid_parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Conference? parse_item_node(StanzaNode item_node, string id) {
|
||||||
|
Conference conference = new Conference();
|
||||||
|
Jid? jid_parsed = Jid.parse(id);
|
||||||
|
if (jid_parsed == null || jid_parsed.resourcepart != null) return null;
|
||||||
|
conference.jid = jid_parsed;
|
||||||
|
|
||||||
|
StanzaNode? conference_node = item_node.get_subnode("conference", NS_URI);
|
||||||
|
if (conference_node == null) return null;
|
||||||
|
|
||||||
|
conference.name = conference_node.get_attribute("name", NS_URI);
|
||||||
|
conference.autojoin = conference_node.get_attribute("autojoin", NS_URI) == "true";
|
||||||
|
conference.nick = conference_node.get_deep_string_content("nick");
|
||||||
|
return conference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void attach(XmppStream stream) {
|
||||||
|
stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NS_URI, on_pupsub_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void detach(XmppStream stream) { }
|
||||||
|
|
||||||
|
public override string get_ns() { return NS_URI; }
|
||||||
|
public override string get_id() { return IDENTITY.id; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Flag : XmppStreamFlag {
|
||||||
|
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "bookmarks2");
|
||||||
|
|
||||||
|
public Flag(HashMap<Jid, Conference> conferences) {
|
||||||
|
this.conferences = conferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<Jid, Conference> conferences = new HashMap<Jid, Conference>(Jid.hash_func, Jid.equals_func);
|
||||||
|
|
||||||
|
public override string get_ns() { return NS_URI; }
|
||||||
|
public override string get_id() { return IDENTITY.id; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue