aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdino/src/service/module_manager.vala1
-rw-r--r--libdino/src/service/muc_manager.vala145
-rw-r--r--main/src/ui/add_conversation/add_groupchat_dialog.vala7
-rw-r--r--main/src/ui/add_conversation/conference_list.vala38
-rw-r--r--plugins/omemo/src/protocol/stream_module.vala4
-rw-r--r--xmpp-vala/CMakeLists.txt7
-rw-r--r--xmpp-vala/src/module/bookmarks_provider.vala17
-rw-r--r--xmpp-vala/src/module/conference.vala19
-rw-r--r--xmpp-vala/src/module/xep/0048_bookmarks.vala80
-rw-r--r--xmpp-vala/src/module/xep/0048_bookmarks/conference.vala92
-rw-r--r--xmpp-vala/src/module/xep/0048_bookmarks/module.vala89
-rw-r--r--xmpp-vala/src/module/xep/0048_conference.vala92
-rw-r--r--xmpp-vala/src/module/xep/0060_pubsub.vala88
-rw-r--r--xmpp-vala/src/module/xep/0084_user_avatars.vala4
-rw-r--r--xmpp-vala/src/module/xep/0402_bookmarks2.vala116
15 files changed, 530 insertions, 269 deletions
diff --git a/libdino/src/service/module_manager.vala b/libdino/src/service/module_manager.vala
index 2b1567a0..a3f56652 100644
--- a/libdino/src/service/module_manager.vala
+++ b/libdino/src/service/module_manager.vala
@@ -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.PrivateXmlStorage.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 Xmpp.MessageModule());
module_map[account].add(new Xep.MessageArchiveManagement.Module());
diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala
index 392339c1..c1ef2d80 100644
--- a/libdino/src/service/muc_manager.vala
+++ b/libdino/src/service/muc_manager.vala
@@ -14,13 +14,15 @@ public class MucManager : StreamInteractionModule, Object {
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 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 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 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 HashMap<Account, BookmarksProvider> bookmarks_provider = new HashMap<Account, BookmarksProvider>(Account.hash_func, Account.equals_func);
public static void start(StreamInteractor stream_interactor) {
MucManager m = new MucManager(stream_interactor);
stream_interactor.add_module(m);
@@ -52,7 +54,7 @@ public class MucManager : StreamInteractionModule, Object {
public void part(Account account, Jid jid) {
XmppStream? stream = stream_interactor.get_stream(account);
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);
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;
}
- 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);
- 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);
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);
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);
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);
}
});
- 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);
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) {
- 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);
- }
- }
- }
- });
+ private async void on_stream_negotiated(Account account, XmppStream stream) {
+ if (bookmarks_provider[account] == null) return;
+
+ Set<Conference>? conferences = yield bookmarks_provider[account].get_conferences(stream);
+
+ if (conferences == null) {
+ join_all_active(account);
+ } else {
+ sync_autojoin_active(account, conferences);
+ }
}
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
+ set_autojoin(account, 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);
@@ -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);
- 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);
- }
+ foreach (Conference conference in conferences) {
+ sync_autojoin_state(account, conference.jid, conference, conversations);
}
}
- 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;
+ private void sync_autojoin_state(Account account, Jid jid, Conference? conference, Gee.List<Conversation>? conversations_ = null) {
+ Gee.List<Conversation> conversations = conversations_ ?? stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account);
+
+ if (conference != null && conference.autojoin) {
+ // Join if we should join
bool is_active = false;
foreach (Conversation conversation in conversations) {
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);
}
+ } 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) {
- stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
+ private void set_autojoin(Account account, XmppStream stream, Jid jid, string? nick, string? password) {
+ bookmarks_provider[account].get_conferences.begin(stream, (_, res) => {
+ Set<Conference>? conferences = bookmarks_provider[account].get_conferences.end(res);
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) {
+
+ Conference changed = new Xep.Bookmarks.Bookmarks1Conference(jid) { nick=nick, password=password, autojoin=true };
+ foreach (Conference conference in conferences) {
+ if (conference.jid.equals(jid)) {
if (!conference.autojoin) {
- conference.autojoin = true;
- stream.get_module(Xep.Bookmarks.Module.IDENTITY).set_conferences(stream, conferences);
+ Conference new_conference = new Conference();
+ 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;
}
}
- 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) {
- stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, (stream, conferences) => {
+ private void unset_autojoin(Account account, XmppStream stream, Jid jid) {
+ bookmarks_provider[account].get_conferences.begin(stream, (_, res) => {
+ Set<Conference>? conferences = bookmarks_provider[account].get_conferences.end(res);
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) {
- conference.autojoin = false;
- stream.get_module(Xep.Bookmarks.Module.IDENTITY).set_conferences(stream, conferences);
+ Conference new_conference = new Conference();
+ 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;
}
}
diff --git a/main/src/ui/add_conversation/add_groupchat_dialog.vala b/main/src/ui/add_conversation/add_groupchat_dialog.vala
index 53359813..33a3a455 100644
--- a/main/src/ui/add_conversation/add_groupchat_dialog.vala
+++ b/main/src/ui/add_conversation/add_groupchat_dialog.vala
@@ -19,7 +19,7 @@ protected class AddGroupchatDialog : Gtk.Dialog {
[GtkChild] private Entry nick_entry;
private StreamInteractor stream_interactor;
- private Xmpp.Xep.Bookmarks.Conference? edit_conference = null;
+ private Conference? edit_conference = null;
private bool alias_entry_changed = false;
public AddGroupchatDialog(StreamInteractor stream_interactor) {
@@ -36,7 +36,7 @@ protected class AddGroupchatDialog : Gtk.Dialog {
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);
edit_conference = conference;
ok_button.label = _("Save");
@@ -65,7 +65,8 @@ protected class AddGroupchatDialog : Gtk.Dialog {
}
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.name = alias_entry.text;
if (edit_conference == null) {
diff --git a/main/src/ui/add_conversation/conference_list.vala b/main/src/ui/add_conversation/conference_list.vala
index 2f52558d..435d42e0 100644
--- a/main/src/ui/add_conversation/conference_list.vala
+++ b/main/src/ui/add_conversation/conference_list.vala
@@ -2,6 +2,7 @@ using Gee;
using Gtk;
using Xmpp;
+using Xmpp.Xep.Bookmarks;
using Dino.Entities;
namespace Dino.Ui {
@@ -11,7 +12,8 @@ protected class ConferenceList : FilterableList {
public signal void conversation_selected(Conversation? conversation);
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) {
this.stream_interactor = stream_interactor;
@@ -26,20 +28,42 @@ protected class ConferenceList : FilterableList {
});
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() {
@foreach((widget) => { remove(widget); });
foreach (Account account in lists.keys) {
- foreach (Xep.Bookmarks.Conference conference in lists[account]) {
- add(new ConferenceListRow(stream_interactor, conference, account));
+ foreach (Conference conference in lists[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) {
lists.unset(account);
} else {
@@ -78,9 +102,9 @@ protected class ConferenceList : FilterableList {
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.account = account;
this.bookmark = bookmark;
diff --git a/plugins/omemo/src/protocol/stream_module.vala b/plugins/omemo/src/protocol/stream_module.vala
index 9a1bc75a..95ba4c85 100644
--- a/plugins/omemo/src/protocol/stream_module.vala
+++ b/plugins/omemo/src/protocol/stream_module.vala
@@ -75,7 +75,7 @@ public class StreamModule : XmppStreamModule {
if (!am_on_devicelist) {
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()));
- 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);
}
@@ -281,7 +281,7 @@ public class StreamModule : XmppStreamModule {
}
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() {
diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt
index b945f9d0..5836f96f 100644
--- a/xmpp-vala/CMakeLists.txt
+++ b/xmpp-vala/CMakeLists.txt
@@ -19,6 +19,8 @@ SOURCES
"src/core/xmpp_stream.vala"
"src/module/bind.vala"
+ "src/module/bookmarks_provider.vala"
+ "src/module/conference.vala"
"src/module/iq/module.vala"
"src/module/iq/stanza.vala"
"src/module/jid.vala"
@@ -39,6 +41,9 @@ SOURCES
"src/module/tls.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/0030_service_discovery/flag.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/status_code.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/0054_vcard/module.vala"
"src/module/xep/0060_pubsub.vala"
diff --git a/xmpp-vala/src/module/bookmarks_provider.vala b/xmpp-vala/src/module/bookmarks_provider.vala
new file mode 100644
index 00000000..69d2efa2
--- /dev/null
+++ b/xmpp-vala/src/module/bookmarks_provider.vala
@@ -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);
+}
+
+}
diff --git a/xmpp-vala/src/module/conference.vala b/xmpp-vala/src/module/conference.vala
new file mode 100644
index 00000000..ee1be6b6
--- /dev/null
+++ b/xmpp-vala/src/module/conference.vala
@@ -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);
+ }
+}
+
+}
diff --git a/xmpp-vala/src/module/xep/0048_bookmarks.vala b/xmpp-vala/src/module/xep/0048_bookmarks.vala
new file mode 100644
index 00000000..8454d711
--- /dev/null
+++ b/xmpp-vala/src/module/xep/0048_bookmarks.vala
@@ -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; }
+}
+
+}
diff --git a/xmpp-vala/src/module/xep/0048_bookmarks/conference.vala b/xmpp-vala/src/module/xep/0048_bookmarks/conference.vala
deleted file mode 100644
index 7f80490b..00000000
--- a/xmpp-vala/src/module/xep/0048_bookmarks/conference.vala
+++ /dev/null
@@ -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;
- }
-}
-
-}
diff --git a/xmpp-vala/src/module/xep/0048_bookmarks/module.vala b/xmpp-vala/src/module/xep/0048_bookmarks/module.vala
deleted file mode 100644
index 2c16f5f0..00000000
--- a/xmpp-vala/src/module/xep/0048_bookmarks/module.vala
+++ /dev/null
@@ -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;
- }
-}
-
-}
diff --git a/xmpp-vala/src/module/xep/0048_conference.vala b/xmpp-vala/src/module/xep/0048_conference.vala
new file mode 100644
index 00000000..d78a2685
--- /dev/null
+++ b/xmpp-vala/src/module/xep/0048_conference.vala
@@ -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;
+ }
+}
+
+}
diff --git a/xmpp-vala/src/module/xep/0060_pubsub.vala b/xmpp-vala/src/module/xep/0060_pubsub.vala
index 91f5525d..434e9a7e 100644
--- a/xmpp-vala/src/module/xep/0060_pubsub.vala
+++ b/xmpp-vala/src/module/xep/0060_pubsub.vala
@@ -21,6 +21,24 @@ namespace Xmpp.Xep.Pubsub {
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 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)));
@@ -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 publish_node = new StanzaNode.build("publish", NS_URI).put_attribute("node", node_id);
pubsub_node.put_node(publish_node);
@@ -43,7 +61,7 @@ namespace Xmpp.Xep.Pubsub {
items_node.put_node(content);
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);
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" };
form_type_field.set_value_string(NS_URI + "#publish-options");
data_form.add_field(form_type_field);
- DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="pubsub#access_model" };
- field.set_value_string(access_model);
- data_form.add_field(field);
+ if (access_model != null) {
+ DataForms.DataForm.Field field = new DataForms.DataForm.Field() { var="pubsub#access_model" };
+ 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());
}
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) {
@@ -82,14 +130,30 @@ namespace Xmpp.Xep.Pubsub {
public override string get_id() { return IDENTITY.id; }
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 items_node = event_node.get_subnode("items", NS_URI_EVENT); if (items_node == null) return;
- StanzaNode item_node = items_node.get_subnode("item", NS_URI_EVENT); if (item_node == null) return;
+ StanzaNode event_node = message.stanza.get_subnode("event", NS_URI_EVENT);
+ if (event_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 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.sub_nodes[0]);
+
+ StanzaNode? item_node = items_node.get_subnode("item", NS_URI_EVENT);
+ 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);
+ }
}
+
}
}
diff --git a/xmpp-vala/src/module/xep/0084_user_avatars.vala b/xmpp-vala/src/module/xep/0084_user_avatars.vala
index 51c2a563..229b2e12 100644
--- a/xmpp-vala/src/module/xep/0084_user_avatars.vala
+++ b/xmpp-vala/src/module/xep/0084_user_avatars.vala
@@ -18,7 +18,7 @@ namespace Xmpp.Xep.UserAvatars {
string sha1 = Checksum.compute_for_data(ChecksumType.SHA1, image);
StanzaNode data_node = new StanzaNode.build("data", NS_URI_DATA).add_self_xmlns()
.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 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("type", "image/png");
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) {
diff --git a/xmpp-vala/src/module/xep/0402_bookmarks2.vala b/xmpp-vala/src/module/xep/0402_bookmarks2.vala
new file mode 100644
index 00000000..cbe6ea45
--- /dev/null
+++ b/xmpp-vala/src/module/xep/0402_bookmarks2.vala
@@ -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; }
+}
+
+}