aboutsummaryrefslogtreecommitdiff
path: root/xmpp-vala
diff options
context:
space:
mode:
Diffstat (limited to 'xmpp-vala')
-rw-r--r--xmpp-vala/meson.build1
-rw-r--r--xmpp-vala/src/module/bind.vala2
-rw-r--r--xmpp-vala/src/module/jid.vala200
-rw-r--r--xmpp-vala/src/module/roster/item.vala2
-rw-r--r--xmpp-vala/src/module/stanza.vala80
-rw-r--r--xmpp-vala/src/module/xep/0030_service_discovery/items_result.vala2
-rw-r--r--xmpp-vala/src/module/xep/0045_muc/module.vala10
-rw-r--r--xmpp-vala/src/module/xep/0048_conference.vala2
-rw-r--r--xmpp-vala/src/module/xep/0065_socks5_bytestreams.vala2
-rw-r--r--xmpp-vala/src/module/xep/0166_jingle/jingle_module.vala2
-rw-r--r--xmpp-vala/src/module/xep/0166_jingle/session.vala2
-rw-r--r--xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala2
-rw-r--r--xmpp-vala/src/module/xep/0260_jingle_socks5_bytestreams.vala2
-rw-r--r--xmpp-vala/src/module/xep/0298_coin.vala2
-rw-r--r--xmpp-vala/src/module/xep/0313_message_archive_management.vala2
-rw-r--r--xmpp-vala/src/module/xep/0388_extensible_sasl_profile.vala2
-rw-r--r--xmpp-vala/src/module/xep/0402_bookmarks2.vala4
-rw-r--r--xmpp-vala/src/module/xep/0461_replies.vala2
-rw-r--r--xmpp-vala/src/weak_map.vala119
-rw-r--r--xmpp-vala/tests/jid.vala14
20 files changed, 349 insertions, 105 deletions
diff --git a/xmpp-vala/meson.build b/xmpp-vala/meson.build
index f0ba7260..85bdaadc 100644
--- a/xmpp-vala/meson.build
+++ b/xmpp-vala/meson.build
@@ -138,6 +138,7 @@ sources = files(
'src/module/xep/0482_call_invites.vala',
'src/file_content_type.vala',
'src/util.vala',
+ 'src/weak_map.vala',
)
c_args = [
'-DG_LOG_DOMAIN="xmpp-vala"',
diff --git a/xmpp-vala/src/module/bind.vala b/xmpp-vala/src/module/bind.vala
index 4df8881a..1b90df92 100644
--- a/xmpp-vala/src/module/bind.vala
+++ b/xmpp-vala/src/module/bind.vala
@@ -19,7 +19,7 @@ namespace Xmpp.Bind {
if (iq.type_ == Iq.Stanza.TYPE_RESULT) {
try {
- flag.my_jid = new Jid(iq.stanza.get_subnode("jid", NS_URI, true).get_string_content());
+ flag.my_jid = Jid.from_string(iq.stanza.get_subnode("jid", NS_URI, true).get_string_content());
flag.finished = true;
bound_to_resource(stream, flag.my_jid);
} catch (InvalidJidError e) {
diff --git a/xmpp-vala/src/module/jid.vala b/xmpp-vala/src/module/jid.vala
index d5dea870..39f93825 100644
--- a/xmpp-vala/src/module/jid.vala
+++ b/xmpp-vala/src/module/jid.vala
@@ -1,21 +1,136 @@
namespace Xmpp {
-public class Jid {
- public string? localpart;
- public string domainpart;
- public string? resourcepart;
+public class Jid : Object {
+ public string? localpart {
+ get {
+ if (level == Level.BARE) return part;
+ if (level == Level.FULL && parent.level == Level.BARE) return parent.part;
+ return null;
+ }
+ }
+ public string domainpart {
+ get {
+ if (level == Level.DOMAIN) return part;
+ return parent.domainpart;
+ }
+ }
+ public string? resourcepart {
+ get {
+ if (level == Level.FULL) return part;
+ return null;
+ }
+ }
public Jid bare_jid {
- owned get { return is_bare() ? this : new Jid.intern(null, localpart, domainpart, null); }
+ get {
+ if (level == Level.FULL) return parent;
+ return this;
+ }
}
public Jid domain_jid {
- owned get { return is_domain() ? this : new Jid.intern(domainpart, null, domainpart, null); }
+ get {
+ if (level == Level.DOMAIN) return this;
+ return parent.domain_jid;
+ }
+ }
+
+ private static WeakMap<string, Jid> INTERNED = new WeakMap<string, Jid>();
+
+ enum Level {
+ DOMAIN,
+ BARE,
+ FULL
+ }
+ private Level level;
+ private Jid? parent;
+ private string part;
+ private string? jid;
+
+ private Jid() {}
+
+ private Jid.domain(string domainpart) throws InvalidJidError {
+ this.level = Level.DOMAIN;
+ this.part = domainpart;
+ this.jid = this.part;
+ }
+
+ private Jid.bare(string localpart, Jid parent, string jid) throws InvalidJidError {
+ this.level = Level.BARE;
+ this.parent = parent;
+ this.part = localpart;
+ this.jid = jid;
+ }
+
+ private Jid.full(Jid parent, string resourcepart, string jid) throws InvalidJidError {
+ this.level = Level.FULL;
+ this.parent = parent;
+ this.part = resourcepart;
+ this.jid = jid;
}
- private string jid;
+ private static Jid get_interned(string jid) {
+ if (INTERNED == null) new Jid();
+ return INTERNED.get(jid);
+ }
+
+ private static Jid from_domain(string domainpart) throws InvalidJidError {
+ if (domainpart.length == 0) throw new InvalidJidError.EMPTY_DOMAIN("Domain is empty");
+
+ Jid result = get_interned(domainpart);
+ if (result != null) return result;
+
+ int domain_length = domainpart.length;
+ if (domainpart[domain_length - 1] == '.') domain_length--;
+ string prepared_domainpart = prepare(idna_decode(domainpart, domain_length), ICU.PrepType.RFC3491_NAMEPREP);
+
+ result = get_interned(prepared_domainpart);
+ if (result != null) {
+ INTERNED.set(domainpart, result);
+ return result;
+ }
+
+ idna_verify(prepared_domainpart);
+ result = new Jid.domain(prepared_domainpart);
+ INTERNED.set(prepared_domainpart, result);
+ INTERNED.set(domainpart, result);
+ return result;
+ }
+
+ private static Jid from_bare(string localpart, Jid parent) throws InvalidJidError {
+ if (localpart.length == 0) throw new InvalidJidError.EMPTY_LOCAL("Localpart is empty but non-null");
+ if (parent.level != Level.DOMAIN) throw new InvalidJidError.UNKNOWN("Parent of bare jid was not a domain");
+
+ string prepared_localpart = prepare(localpart, ICU.PrepType.RFC3920_NODEPREP);
+ string prepared_jid = "%s@%s".printf(prepared_localpart, parent.part);
+
+ Jid result = get_interned(prepared_jid);
+ if (result != null) return result;
+
+ result = new Jid.bare(prepared_localpart, parent, prepared_jid);
+ INTERNED.set(prepared_jid, result);
+ return result;
+ }
+
+ private static Jid from_full(Jid parent, string resourcepart) throws InvalidJidError {
+ if (resourcepart.length == 0) throw new InvalidJidError.EMPTY_RESOURCE("Resource is empty but non-null");
+ if (parent.level > Level.BARE) throw new InvalidJidError.UNKNOWN("Parent of full jid was not a bare jid or domain");
+
+ string prepared_resourcepart = prepare(resourcepart, ICU.PrepType.RFC3920_RESOURCEPREP);
+ string prepared_jid = "%s/%s".printf(parent.jid, prepared_resourcepart);
+
+ Jid result = get_interned(prepared_jid);
+ if (result != null) return result;
+
+ result = new Jid.full(parent, prepared_resourcepart, prepared_jid);
+ INTERNED.set(prepared_jid, result);
+ return result;
+ }
+
+ public static Jid from_string(string jid) throws InvalidJidError {
+ Jid result = get_interned(jid);
+ if (result != null) return result;
- public Jid(string jid) throws InvalidJidError {
int slash_index = jid.index_of("/");
int at_index = jid.index_of("@");
if (at_index > slash_index && slash_index != -1) at_index = -1;
@@ -35,37 +150,27 @@ public class Jid {
domainpart = jid.slice(at_index + 1, slash_index);
}
}
-
- this.components(localpart, domainpart, resourcepart);
+ result = from_components(localpart, domainpart, resourcepart);
+ INTERNED.set(jid, result);
+ return result;
}
- private Jid.intern(owned string? jid, owned string? localpart, owned string domainpart, owned string? resourcepart) {
- this.jid = (owned) jid;
- this.localpart = (owned) localpart;
- this.domainpart = (owned) domainpart;
- this.resourcepart = (owned) resourcepart;
- }
-
- public Jid.components(string? localpart, string domainpart, string? resourcepart) throws InvalidJidError {
- // TODO verify and normalize all parts
- if (domainpart.length == 0) throw new InvalidJidError.EMPTY_DOMAIN("Domain is empty");
- if (localpart != null && localpart.length == 0) throw new InvalidJidError.EMPTY_LOCAL("Localpart is empty but non-null");
- if (resourcepart != null && resourcepart.length == 0) throw new InvalidJidError.EMPTY_RESOURCE("Resource is empty but non-null");
- string domain = domainpart[domainpart.length - 1] == '.' ? domainpart.substring(0, domainpart.length - 1) : domainpart;
- if (domain.contains("xn--")) {
- domain = idna_decode(domain);
+ public static Jid from_components(string? localpart, string domainpart, string? resourcepart) throws InvalidJidError {
+ Jid jid = from_domain(domainpart);
+ if (localpart != null) {
+ jid = from_bare(localpart, jid);
}
- this.localpart = prepare(localpart, ICU.PrepType.RFC3920_NODEPREP);
- this.domainpart = prepare(domain, ICU.PrepType.RFC3491_NAMEPREP);
- this.resourcepart = prepare(resourcepart, ICU.PrepType.RFC3920_RESOURCEPREP);
- idna_verify(this.domainpart);
+ if (resourcepart != null) {
+ jid = from_full(jid, resourcepart);
+ }
+ return jid;
}
- private static string idna_decode(string src) throws InvalidJidError {
+ private static string idna_decode(string src, int src_length = -1) throws InvalidJidError {
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
ICU.IDNAInfo info;
char[] dest = new char[src.length * 2];
- ICU.IDNA.openUTS46(ICU.IDNAOptions.DEFAULT, ref status).nameToUnicodeUTF8(src, -1, dest, out info, ref status);
+ ICU.IDNA.openUTS46(ICU.IDNAOptions.DEFAULT, ref status).nameToUnicodeUTF8(src, src_length, dest, out info, ref status);
if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
} else if (status.is_failure() || info.errors > 0) {
@@ -112,33 +217,23 @@ public class Jid {
}
public Jid with_resource(string? resourcepart) throws InvalidJidError {
- return new Jid.components(localpart, domainpart, resourcepart);
+ if (resourcepart == null) return bare_jid;
+ return Jid.from_full(bare_jid, resourcepart);
}
public bool is_domain() {
- return localpart == null && resourcepart == null;
+ return level == Level.DOMAIN;
}
public bool is_bare() {
- return resourcepart == null;
+ return level <= Level.BARE;
}
public bool is_full() {
- return localpart != null && resourcepart != null;
+ return level == Level.FULL;
}
- public string to_string() {
- if (jid == null) {
- if (localpart != null && resourcepart != null) {
- jid = @"$localpart@$domainpart/$resourcepart";
- } else if (localpart != null) {
- jid = @"$localpart@$domainpart";
- } else if (resourcepart != null) {
- jid = @"$domainpart/$resourcepart";
- } else {
- jid = domainpart;
- }
- }
+ public unowned string to_string() {
return jid;
}
@@ -151,11 +246,16 @@ public class Jid {
}
public static new bool equals_bare_func(Jid jid1, Jid jid2) {
- return jid1.localpart == jid2.localpart && jid1.domainpart == jid2.domainpart;
+ return equals_func(jid1.bare_jid, jid2.bare_jid);
}
- public static bool equals_func(Jid jid1, Jid jid2) {
- return equals_bare_func(jid1, jid2) && jid1.resourcepart == jid2.resourcepart;
+ public static bool equals_func(Jid? jid1, Jid? jid2) {
+ if (jid1 == null && jid2 == null) return true;
+ if (jid1 == null || jid2 == null) return false;
+ if (jid1 == jid2) return true;
+ bool res = jid1.level == jid2.level && jid1.part == jid2.part && equals_func(jid1.parent, jid2.parent);
+ if (res) warning("JIDs considered equal, but are not same instance");
+ return res;
}
public static new uint hash_bare_func(Jid jid) {
diff --git a/xmpp-vala/src/module/roster/item.vala b/xmpp-vala/src/module/roster/item.vala
index 4c9f30ef..e388bd06 100644
--- a/xmpp-vala/src/module/roster/item.vala
+++ b/xmpp-vala/src/module/roster/item.vala
@@ -18,7 +18,7 @@ public class Item {
public Jid? jid {
get {
try {
- return jid_ ?? (jid_ = new Jid(stanza_node.get_attribute("jid")));
+ return jid_ ?? (jid_ = Jid.from_string(stanza_node.get_attribute("jid")));
} catch (InvalidJidError e) {
warning("Ignoring invalid Jid in roster entry: %s", e.message);
return null;
diff --git a/xmpp-vala/src/module/stanza.vala b/xmpp-vala/src/module/stanza.vala
index 3b029197..33816a6b 100644
--- a/xmpp-vala/src/module/stanza.vala
+++ b/xmpp-vala/src/module/stanza.vala
@@ -13,44 +13,59 @@ public class Stanza : Object {
private Jid? from_;
private Jid? to_;
- public virtual Jid? from {
- owned get {
- string? from_attribute = stanza.get_attribute(ATTRIBUTE_FROM);
- // "when a client receives a stanza that does not include a 'from' attribute, it MUST assume that the stanza
- // is from the user's account on the server." (RFC6120 8.1.2.1)
- if (from_attribute != null) {
- try {
- return from_ = new Jid(from_attribute);
- } catch (InvalidJidError e) {
- warning("Ignoring invalid from Jid: %s", e.message);
+ public Jid? from {
+ get {
+ if (from_ == null) {
+ string? from_attribute = stanza.get_attribute(ATTRIBUTE_FROM);
+ if (from_attribute != null) {
+ try {
+ from_ = Jid.from_string(from_attribute);
+ } catch (InvalidJidError e) {
+ warning("Ignoring invalid from Jid: %s", e.message);
+ }
+ }
+ // "when a client receives a stanza that does not include a 'from' attribute, it MUST assume that the stanza
+ // is from the user's account on the server." (RFC6120 8.1.2.1)
+ if (from_ == null && my_jid != null) {
+ from_ = my_jid.bare_jid;
}
}
- if (my_jid != null) {
- return my_jid.bare_jid;
- }
- return null;
+ return from_;
+ }
+ set {
+ from_ = value;
+ stanza.set_attribute(ATTRIBUTE_FROM, value.to_string());
}
- set { stanza.set_attribute(ATTRIBUTE_FROM, value.to_string()); }
}
- public virtual string? id {
+ public string? id {
get { return stanza.get_attribute(ATTRIBUTE_ID); }
set { stanza.set_attribute(ATTRIBUTE_ID, value); }
}
- public virtual Jid? to {
- owned get {
- string? to_attribute = stanza.get_attribute(ATTRIBUTE_TO);
- // "if the stanza does not include a 'to' address then the client MUST treat it as if the 'to' address were
- // included with a value of the client's full JID." (RFC6120 8.1.1.1)
- try {
- return to_attribute == null ? my_jid : to_ = new Jid(to_attribute);
- } catch (InvalidJidError e) {
- warning("Ignoring invalid to Jid: %s", e.message);
+ public Jid? to {
+ get {
+ if (to_ == null) {
+ string? to_attribute = stanza.get_attribute(ATTRIBUTE_TO);
+ if (to_attribute != null) {
+ try {
+ to_ = Jid.from_string(to_attribute);
+ } catch (InvalidJidError e) {
+ warning("Ignoring invalid to Jid: %s", e.message);
+ }
+ }
+ // "if the stanza does not include a 'to' address then the client MUST treat it as if the 'to' address were
+ // included with a value of the client's full JID." (RFC6120 8.1.1.1)
+ if (to_ == null) {
+ to_ = my_jid;
+ }
}
- return my_jid;
+ return to_;
+ }
+ set {
+ to_ = value;
+ stanza.set_attribute(ATTRIBUTE_TO, value.to_string());
}
- set { stanza.set_attribute(ATTRIBUTE_TO, value.to_string()); }
}
public virtual string? type_ {
@@ -58,7 +73,16 @@ public class Stanza : Object {
set { stanza.set_attribute(ATTRIBUTE_TYPE, value); }
}
- public StanzaNode stanza;
+ private StanzaNode stanza_;
+ public StanzaNode stanza {
+ get { return stanza_; }
+ set {
+ stanza_ = value;
+ // Invalidate caches
+ from_ = null;
+ to_ = null;
+ }
+ }
public Stanza.incoming(StanzaNode stanza, Jid? my_jid) {
this.stanza = stanza;
diff --git a/xmpp-vala/src/module/xep/0030_service_discovery/items_result.vala b/xmpp-vala/src/module/xep/0030_service_discovery/items_result.vala
index 105da893..9fdae90b 100644
--- a/xmpp-vala/src/module/xep/0030_service_discovery/items_result.vala
+++ b/xmpp-vala/src/module/xep/0030_service_discovery/items_result.vala
@@ -10,7 +10,7 @@ public class ItemsResult {
ArrayList<Item> ret = new ArrayList<Item>();
foreach (StanzaNode feature_node in iq.stanza.get_subnode("query", NS_URI_ITEMS).get_subnodes("item", NS_URI_ITEMS)) {
try {
- ret.add(new Item(new Jid(feature_node.get_attribute("jid", NS_URI_ITEMS)),
+ ret.add(new Item(Jid.from_string(feature_node.get_attribute("jid", NS_URI_ITEMS)),
feature_node.get_attribute("name", NS_URI_ITEMS),
feature_node.get_attribute("node", NS_URI_ITEMS)));
} catch (InvalidJidError e) {
diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala
index bdaabb3e..ad929b00 100644
--- a/xmpp-vala/src/module/xep/0045_muc/module.vala
+++ b/xmpp-vala/src/module/xep/0045_muc/module.vala
@@ -377,7 +377,7 @@ public class Module : XmppStreamModule {
string? jid_ = x_node.get_deep_attribute("item", "jid");
if (jid_ != null) {
try {
- Jid real_jid = new Jid(jid_);
+ Jid real_jid = Jid.from_string(jid_);
flag.set_real_jid(presence.from, real_jid);
if (affiliation != null) {
stream.get_flag(Flag.IDENTITY).set_offline_member(presence.from, real_jid, affiliation);
@@ -496,7 +496,7 @@ public class Module : XmppStreamModule {
string? affiliation_ = item.get_attribute("affiliation");
if (jid__ != null && affiliation_ != null) {
try {
- Jid jid_ = new Jid(jid__);
+ Jid jid_ = Jid.from_string(jid__);
stream.get_flag(Flag.IDENTITY).set_offline_member(iq_result.from, jid_, parse_affiliation(affiliation_));
ret_jids.add(jid_);
} catch (InvalidJidError e) {
@@ -574,7 +574,7 @@ public class ReceivedPipelineListener : StanzaListener<MessageStanza> {
Jid? from_jid = null;
try {
string from = invite_node.get_attribute("from");
- if (from != null) from_jid = new Jid(from);
+ if (from != null) from_jid = Jid.from_string(from);
} catch (InvalidJidError e) {
warning("Received invite from invalid jid: %s", e.message);
}
@@ -594,7 +594,7 @@ public class ReceivedPipelineListener : StanzaListener<MessageStanza> {
var affiliations = new HashMap<Jid, Affiliation>();
foreach (StanzaNode item_node in item_nodes) {
string jid_str = item_node.get_attribute("jid", Muc.NS_URI_USER);
- Jid real_jid = new Jid(jid_str);
+ Jid real_jid = Jid.from_string(jid_str);
string affiliation_str = item_node.get_attribute("affiliation", Muc.NS_URI_USER);
Muc.Affiliation affiliation = Muc.Module.parse_affiliation(affiliation_str);
@@ -622,7 +622,7 @@ public class ReceivedPipelineListener : StanzaListener<MessageStanza> {
if (var_ == "muc#jid"){
StanzaNode? value_node = field_node.get_subnode("value", DataForms.NS_URI);
try {
- if (value_node != null) from_jid = new Jid(value_node.get_string_content());
+ if (value_node != null) from_jid = Jid.from_string(value_node.get_string_content());
} catch (InvalidJidError e) {
return false;
}
diff --git a/xmpp-vala/src/module/xep/0048_conference.vala b/xmpp-vala/src/module/xep/0048_conference.vala
index b61de1c0..ee0188de 100644
--- a/xmpp-vala/src/module/xep/0048_conference.vala
+++ b/xmpp-vala/src/module/xep/0048_conference.vala
@@ -23,7 +23,7 @@ public class Bookmarks1Conference : Conference {
public override Jid? jid {
get {
try {
- return jid_ ?? (jid_ = new Jid(stanza_node.get_attribute(ATTRIBUTE_JID)));
+ return jid_ ?? (jid_ = Jid.from_string(stanza_node.get_attribute(ATTRIBUTE_JID)));
} catch (InvalidJidError e) {
return null;
}
diff --git a/xmpp-vala/src/module/xep/0065_socks5_bytestreams.vala b/xmpp-vala/src/module/xep/0065_socks5_bytestreams.vala
index c184877c..97674f3f 100644
--- a/xmpp-vala/src/module/xep/0065_socks5_bytestreams.vala
+++ b/xmpp-vala/src/module/xep/0065_socks5_bytestreams.vala
@@ -69,7 +69,7 @@ public class Module : XmppStreamModule, Iq.Handler {
string? jid_str = stream_host.get_attribute("jid");
Jid? jid = null;
try {
- jid = jid_str != null ? new Jid(jid_str) : null;
+ jid = jid_str != null ? Jid.from_string(jid_str) : null;
} catch (InvalidJidError ignored) { }
int port = stream_host.get_attribute_int("port");
if (host == null || jid == null || port <= 0 || port > 65535) {
diff --git a/xmpp-vala/src/module/xep/0166_jingle/jingle_module.vala b/xmpp-vala/src/module/xep/0166_jingle/jingle_module.vala
index cdcb9130..5e3b69c2 100644
--- a/xmpp-vala/src/module/xep/0166_jingle/jingle_module.vala
+++ b/xmpp-vala/src/module/xep/0166_jingle/jingle_module.vala
@@ -165,7 +165,7 @@ namespace Xmpp.Xep.Jingle {
string? muji_room_str = iq.stanza.get_deep_attribute(NS_URI + ":jingle", Xep.Muji.NS_URI + ":muji", "room");
if (muji_room_str != null) {
try {
- session.muji_room = new Jid(muji_room_str);
+ session.muji_room = Jid.from_string(muji_room_str);
} catch (InvalidJidError e) {
// Ignore
}
diff --git a/xmpp-vala/src/module/xep/0166_jingle/session.vala b/xmpp-vala/src/module/xep/0166_jingle/session.vala
index 53a9c58d..22e8e978 100644
--- a/xmpp-vala/src/module/xep/0166_jingle/session.vala
+++ b/xmpp-vala/src/module/xep/0166_jingle/session.vala
@@ -257,7 +257,7 @@ public class Xmpp.Xep.Jingle.Session : Object {
Jid responder = iq.from;
if (responder_str != null) {
try {
- responder = new Jid(responder_str);
+ responder = Jid.from_string(responder_str);
} catch (InvalidJidError e) {
warning("Received invalid session accept: %s", e.message);
}
diff --git a/xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala b/xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala
index 2ccab33d..8c2e04fd 100644
--- a/xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala
+++ b/xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala
@@ -23,7 +23,7 @@ namespace Xmpp.Xep.DirectMucInvitations {
if (room_str == null) return;
Jid? room_jid = null;
try {
- room_jid = new Jid(room_str);
+ room_jid = Jid.from_string(room_str);
} catch (Error e) {
return;
}
diff --git a/xmpp-vala/src/module/xep/0260_jingle_socks5_bytestreams.vala b/xmpp-vala/src/module/xep/0260_jingle_socks5_bytestreams.vala
index 0fe9ce5f..852cc7eb 100644
--- a/xmpp-vala/src/module/xep/0260_jingle_socks5_bytestreams.vala
+++ b/xmpp-vala/src/module/xep/0260_jingle_socks5_bytestreams.vala
@@ -162,7 +162,7 @@ public class Candidate : Socks5Bytestreams.Proxy {
string? jid_str = candidate.get_attribute("jid");
Jid? jid = null;
try {
- jid = new Jid(jid_str);
+ jid = Jid.from_string(jid_str);
} catch (InvalidJidError ignored) {
}
int port = candidate.get_attribute("port") != null ? candidate.get_attribute_int("port") : 1080;
diff --git a/xmpp-vala/src/module/xep/0298_coin.vala b/xmpp-vala/src/module/xep/0298_coin.vala
index 1a7b6d60..a8c12e07 100644
--- a/xmpp-vala/src/module/xep/0298_coin.vala
+++ b/xmpp-vala/src/module/xep/0298_coin.vala
@@ -44,7 +44,7 @@ namespace Xmpp.Xep.Coin {
// if (!jid_string.has_prefix("xmpp:")) continue; // silk does this wrong
Jid? jid = null;
try {
- jid = new Jid(jid_string.substring(4));
+ jid = Jid.from_string(jid_string.substring(4));
} catch (Error e) {
continue;
}
diff --git a/xmpp-vala/src/module/xep/0313_message_archive_management.vala b/xmpp-vala/src/module/xep/0313_message_archive_management.vala
index 1a7789cb..a9149d4e 100644
--- a/xmpp-vala/src/module/xep/0313_message_archive_management.vala
+++ b/xmpp-vala/src/module/xep/0313_message_archive_management.vala
@@ -118,7 +118,7 @@ public class ReceivedPipelineListener : StanzaListener<MessageStanza> {
}
Jid? inner_from = null;
try {
- inner_from = new Jid(message_node.get_attribute("from"));
+ inner_from = Jid.from_string(message_node.get_attribute("from"));
} catch (InvalidJidError e) {
warning("Received MAM message with invalid from attribute in forwarded message from %s, ignoring", message.from.to_string());
return true;
diff --git a/xmpp-vala/src/module/xep/0388_extensible_sasl_profile.vala b/xmpp-vala/src/module/xep/0388_extensible_sasl_profile.vala
index cfeeb567..f7db524d 100644
--- a/xmpp-vala/src/module/xep/0388_extensible_sasl_profile.vala
+++ b/xmpp-vala/src/module/xep/0388_extensible_sasl_profile.vala
@@ -40,7 +40,7 @@ namespace Xmpp.Xep.ExtensibleSaslProfile {
var authorisation_identifier = node.get_subnode("authorization-identifier", NS_URI);
string jid_string = authorisation_identifier.get_string_content();
- Jid jid = new Jid(jid_string);
+ Jid jid = Jid.from_string(jid_string);
foreach (var inline_provider in inline_activation_providers.values) {
inline_provider.on_bound(stream, jid, node);
diff --git a/xmpp-vala/src/module/xep/0402_bookmarks2.vala b/xmpp-vala/src/module/xep/0402_bookmarks2.vala
index 429f26f5..938af0e9 100644
--- a/xmpp-vala/src/module/xep/0402_bookmarks2.vala
+++ b/xmpp-vala/src/module/xep/0402_bookmarks2.vala
@@ -88,7 +88,7 @@ public class Module : BookmarksProvider, XmppStreamModule {
}
try {
- Jid jid_parsed = new Jid(id);
+ Jid jid_parsed = Jid.from_string(id);
Flag? flag = stream.get_flag(Flag.IDENTITY);
if (flag != null) {
flag.conferences.unset(jid_parsed);
@@ -102,7 +102,7 @@ public class Module : BookmarksProvider, XmppStreamModule {
private Conference? parse_item_node(StanzaNode conference_node, string id) {
Conference conference = new Conference();
try {
- Jid jid_parsed = new Jid(id);
+ Jid jid_parsed = Jid.from_string(id);
if (jid_parsed.resourcepart != null) return null;
conference.jid = jid_parsed;
} catch (InvalidJidError e) {
diff --git a/xmpp-vala/src/module/xep/0461_replies.vala b/xmpp-vala/src/module/xep/0461_replies.vala
index 870df295..af84aa3d 100644
--- a/xmpp-vala/src/module/xep/0461_replies.vala
+++ b/xmpp-vala/src/module/xep/0461_replies.vala
@@ -27,7 +27,7 @@ namespace Xmpp.Xep.Replies {
string? to_str = reply_node.get_attribute("to");
if (to_str == null) return null;
try {
- Jid to_jid = new Jid(to_str);
+ Jid to_jid = Jid.from_string(to_str);
string? id = reply_node.get_attribute("id");
if (id == null) return null;
diff --git a/xmpp-vala/src/weak_map.vala b/xmpp-vala/src/weak_map.vala
new file mode 100644
index 00000000..a7f4bc44
--- /dev/null
+++ b/xmpp-vala/src/weak_map.vala
@@ -0,0 +1,119 @@
+using Gee;
+
+public class WeakMap<K, V> : Gee.AbstractMap<K, V> {
+
+ private HashMap<K, weak V> hash_map;
+ private HashMap<K, WeakNotifyWrapper> notify_map;
+
+ public HashDataFunc<K>? key_hash_func = null;
+ public EqualDataFunc<K>? key_equal_func = null;
+ public EqualDataFunc<V>? value_equal_func = null;
+
+ public WeakMap(owned HashDataFunc<K>? key_hash_func = null, owned EqualDataFunc<K>? key_equal_func = null, owned EqualDataFunc<V>? value_equal_func = null) {
+ if (!typeof(V).is_object()) {
+ error("WeakMap only takes values that are Objects");
+ }
+
+ this.key_hash_func = (owned)key_hash_func;
+ this.key_equal_func = (owned)key_equal_func;
+ this.value_equal_func = (owned)value_equal_func;
+
+ if (this.key_equal_func == null || this.key_equal_func == null || this.value_equal_func == null) {
+ hash_map = new HashMap<K, weak V>();
+ notify_map = new HashMap<K, WeakNotifyWrapper>();
+ } else {
+ hash_map = new HashMap<K, weak V>((v) => { return this.key_hash_func != null ? this.key_hash_func(v) : 0; },
+ (a, b) => { return this.key_equal_func != null ? this.key_equal_func(a, b) : a == b; },
+ (a, b) => { return this.value_equal_func != null ? this.value_equal_func(a, b) : a == b; });
+ notify_map = new HashMap<K, WeakNotifyWrapper>((v) => { return this.key_hash_func != null ? this.key_hash_func(v) : 0; },
+ (a, b) => { return this.key_equal_func != null ? this.key_equal_func(a, b) : a == b; });
+ }
+ }
+
+ public override void clear() {
+ foreach (K key in notify_map.keys) {
+ Object o = (Object) hash_map[key];
+ o.weak_unref(notify_map[key].func);
+ }
+ hash_map.clear();
+ notify_map.clear();
+ }
+
+ public override V @get(K key) {
+ if (!hash_map.has_key(key)) return null;
+
+ var v = hash_map[key];
+
+ return (owned) v;
+ }
+
+ public override bool has(K key, V value) {
+ return has_key(key) && (this.value_equal_func != null ? this.value_equal_func(hash_map[key], value) : hash_map[key] == value);
+ }
+
+ public override bool has_key(K key) {
+ return hash_map.has_key(key);
+ }
+
+ public override Gee.MapIterator<K,V> map_iterator() {
+ assert_not_reached();
+ }
+
+ public override void @set(K key, V value) {
+ assert(value != null);
+
+ unset(key);
+
+ Object v_obj = (Object) value;
+ var notify_wrap = new WeakNotifyWrapper((obj) => {
+ hash_map.unset(key);
+ notify_map.unset(key);
+ });
+ notify_map[key] = notify_wrap;
+ v_obj.weak_ref(notify_wrap.func);
+
+ hash_map[key] = value;
+ }
+
+ public override bool unset(K key, out V value = null) {
+ if (!hash_map.has_key(key)) {
+ value = null;
+ return false;
+ }
+
+ Object v_obj = (Object) hash_map[key];
+ v_obj.weak_unref(notify_map[key].func);
+ notify_map.unset(key);
+ return hash_map.unset(key, out value);
+ }
+ public override Gee.Set<Gee.Map.Entry<K,V>> entries { owned get; }
+
+ public override Gee.Set<K> keys {
+ owned get { return hash_map.keys; }
+ }
+
+ public override bool read_only { get { assert_not_reached(); } }
+
+ public override int size { get { return hash_map.size; } }
+
+ public override Gee.Collection<V> values {
+ owned get {
+ assert_not_reached();
+ }
+ }
+
+ public override void dispose() {
+ foreach (K key in notify_map.keys) {
+ Object o = (Object) hash_map[key];
+ o.weak_unref(notify_map[key].func);
+ }
+ }
+}
+
+internal class WeakNotifyWrapper {
+ public WeakNotify func;
+
+ public WeakNotifyWrapper(owned WeakNotify func) {
+ this.func = (owned) func;
+ }
+} \ No newline at end of file
diff --git a/xmpp-vala/tests/jid.vala b/xmpp-vala/tests/jid.vala
index 90420056..72b8e906 100644
--- a/xmpp-vala/tests/jid.vala
+++ b/xmpp-vala/tests/jid.vala
@@ -42,7 +42,7 @@ class JidTest : Gee.TestCase {
private void test_jid_valid(string jid) {
try {
- new Jid(jid);
+ Jid.from_string(jid);
} catch (Error e) {
fail_if_reached(@"Throws $(e.message)");
}
@@ -50,7 +50,7 @@ class JidTest : Gee.TestCase {
private void test_jid_invalid(string jid) {
try {
- new Jid(jid);
+ Jid.from_string(jid);
fail_if_reached();
} catch (Error e) {
// try {
@@ -63,8 +63,8 @@ class JidTest : Gee.TestCase {
private void test_jids_equal(string jid1, string jid2) {
try {
- var t1 = new Jid(jid1);
- var t2 = new Jid(jid2);
+ var t1 = Jid.from_string(jid1);
+ var t2 = Jid.from_string(jid2);
fail_if_not_eq_str(t1.to_string(), t2.to_string());
} catch (Error e) {
fail_if_reached(@"Throws $(e.message)");
@@ -73,7 +73,7 @@ class JidTest : Gee.TestCase {
private void test_jid_to_string(string jid1, string jid2) {
try {
- var t1 = new Jid(jid1);
+ var t1 = Jid.from_string(jid1);
fail_if_not_eq_str(t1.to_string(), jid2);
} catch (Error e) {
fail_if_reached(@"Throws $(e.message)");
@@ -82,8 +82,8 @@ class JidTest : Gee.TestCase {
private void test_jids_unequal(string jid1, string jid2) {
try {
- var t1 = new Jid(jid1);
- var t2 = new Jid(jid2);
+ var t1 = Jid.from_string(jid1);
+ var t2 = Jid.from_string(jid2);
fail_if_eq_str(t1.to_string(), t2.to_string());
} catch (Error e) {
fail_if_reached(@"Throws $(e.message)");