From 74c29d4df19f97b9b67bbc3c1a963a8729be69fd Mon Sep 17 00:00:00 2001 From: fiaxh Date: Sat, 28 Sep 2019 21:40:43 +0200 Subject: Add Bookmarks2 implementation, introduce bookmarks interfaces --- xmpp-vala/src/module/bookmarks_provider.vala | 17 +++ xmpp-vala/src/module/conference.vala | 19 ++++ xmpp-vala/src/module/xep/0048_bookmarks.vala | 80 ++++++++++++++ .../src/module/xep/0048_bookmarks/conference.vala | 92 ---------------- .../src/module/xep/0048_bookmarks/module.vala | 89 ---------------- xmpp-vala/src/module/xep/0048_conference.vala | 92 ++++++++++++++++ xmpp-vala/src/module/xep/0060_pubsub.vala | 88 +++++++++++++--- xmpp-vala/src/module/xep/0084_user_avatars.vala | 4 +- xmpp-vala/src/module/xep/0402_bookmarks2.vala | 116 +++++++++++++++++++++ 9 files changed, 402 insertions(+), 195 deletions(-) create mode 100644 xmpp-vala/src/module/bookmarks_provider.vala create mode 100644 xmpp-vala/src/module/conference.vala create mode 100644 xmpp-vala/src/module/xep/0048_bookmarks.vala delete mode 100644 xmpp-vala/src/module/xep/0048_bookmarks/conference.vala delete mode 100644 xmpp-vala/src/module/xep/0048_bookmarks/module.vala create mode 100644 xmpp-vala/src/module/xep/0048_conference.vala create mode 100644 xmpp-vala/src/module/xep/0402_bookmarks2.vala (limited to 'xmpp-vala/src/module') 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 conferences); + + public async abstract async Set? 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 IDENTITY = new ModuleIdentity(NS_URI, "0048_bookmarks_module"); + + public async Set? get_conferences(XmppStream stream) { + Set ret = new HashSet(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 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 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? 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? 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? 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 IDENTITY = new ModuleIdentity(NS_URI, "0048_bookmarks_module"); - - public signal void received_conferences(XmppStream stream, Gee.List conferences); - - public delegate void OnResult(XmppStream stream, Gee.List? 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 conferences = get_conferences_from_stanza(node); - listener(stream, conferences); - } - }); - } - - public void set_conferences(XmppStream stream, Gee.List 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 get_conferences_from_stanza(StanzaNode node) { - Gee.List conferences = new ArrayList(); - Gee.List 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? 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? 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 IDENTITY = new ModuleIdentity(NS_URI, "0402_bookmarks2"); + + public async Set? get_conferences(XmppStream stream) { + HashMap? hm = null; + + Flag? flag = stream.get_flag(Flag.IDENTITY); + if (flag != null) { + hm = flag.conferences; + } else { + Gee.List? 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.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(); + 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 IDENTITY = new FlagIdentity(NS_URI, "bookmarks2"); + + public Flag(HashMap conferences) { + this.conferences = conferences; + } + + public HashMap conferences = new HashMap(Jid.hash_func, Jid.equals_func); + + public override string get_ns() { return NS_URI; } + public override string get_id() { return IDENTITY.id; } +} + +} -- cgit v1.2.3-70-g09d2