diff options
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/xmpp')
5 files changed, 158 insertions, 149 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java index f6e6edb8..14f2a648 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java @@ -96,6 +96,7 @@ import de.thedevstack.conversationsplus.xmpp.stanzas.streammgmt.AckPacket; import de.thedevstack.conversationsplus.xmpp.stanzas.streammgmt.EnablePacket; import de.thedevstack.conversationsplus.xmpp.stanzas.streammgmt.RequestPacket; import de.thedevstack.conversationsplus.xmpp.stanzas.streammgmt.ResumePacket; +import de.thedevstack.conversationsplus.xmpp.jid.JidUtil; public class XmppConnection implements Runnable { private static final int DEFAULT_PORT = 5222; @@ -898,7 +899,7 @@ public class XmppConnection implements Runnable { final Element jid = bind.findChild("jid"); if (jid != null && jid.getContent() != null) { try { - account.setResource(Jid.fromString(jid.getContent()).getResourcepart()); + account.setResource(JidUtil.fromString(jid.getContent()).getResourcepart()); } catch (final InvalidJidException e) { // TODO: Handle the case where an external JID is technically invalid? } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/forms/Field.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/forms/Field.java index 88b3155c..0509d473 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/forms/Field.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/forms/Field.java @@ -23,12 +23,12 @@ public class Field extends Element { } public void setValue(String value) { - this.children.clear(); + this.clearChildren(); this.addChild("value").setContent(value); } public void setValues(Collection<String> values) { - this.children.clear(); + this.clearChildren(); for(String value : values) { this.addChild("value").setContent(value); } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/Jid.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/Jid.java index bb32e821..a85c0bed 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/Jid.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/Jid.java @@ -1,22 +1,12 @@ package de.thedevstack.conversationsplus.xmpp.jid; -import android.util.LruCache; - -import net.java.otr4j.session.SessionID; - import java.net.IDN; -import de.thedevstack.conversationsplus.Config; -import gnu.inet.encoding.Stringprep; -import gnu.inet.encoding.StringprepException; - /** * The `Jid' class provides an immutable representation of a JID. */ public final class Jid { - private static LruCache<String,Jid> cache = new LruCache<>(1024); - private final String localpart; private final String domainpart; private final String resourcepart; @@ -37,143 +27,16 @@ public final class Jid { return resourcepart; } - public static Jid fromSessionID(final SessionID id) throws InvalidJidException{ - if (id.getUserID().isEmpty()) { - return Jid.fromString(id.getAccountID()); - } else { - return Jid.fromString(id.getAccountID()+"/"+id.getUserID()); - } - } - - public static Jid fromString(final String jid) throws InvalidJidException { - return Jid.fromString(jid, false); - } - - public static Jid fromString(final String jid, final boolean safe) throws InvalidJidException { - return new Jid(jid, safe); - } - - public static Jid fromParts(final String localpart, - final String domainpart, - final String resourcepart) throws InvalidJidException { - String out; - if (localpart == null || localpart.isEmpty()) { - out = domainpart; - } else { - out = localpart + "@" + domainpart; - } - if (resourcepart != null && !resourcepart.isEmpty()) { - out = out + "/" + resourcepart; - } - return new Jid(out, false); - } - - private Jid(final String jid, final boolean safe) throws InvalidJidException { - if (jid == null) throw new InvalidJidException(InvalidJidException.IS_NULL); - - Jid fromCache = Jid.cache.get(jid); - if (fromCache != null) { - displayjid = fromCache.displayjid; - localpart = fromCache.localpart; - domainpart = fromCache.domainpart; - resourcepart = fromCache.resourcepart; - return; - } - - // Hackish Android way to count the number of chars in a string... should work everywhere. - final int atCount = jid.length() - jid.replace("@", "").length(); - final int slashCount = jid.length() - jid.replace("/", "").length(); - - // Throw an error if there's anything obvious wrong with the JID... - if (jid.isEmpty() || jid.length() > 3071) { - throw new InvalidJidException(InvalidJidException.INVALID_LENGTH); - } - - // Go ahead and check if the localpart or resourcepart is empty. - if (jid.startsWith("@") || (jid.endsWith("@") && slashCount == 0) || jid.startsWith("/") || (jid.endsWith("/") && slashCount < 2)) { - throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER); - } - - String finaljid; - - final int domainpartStart; - final int atLoc = jid.indexOf("@"); - final int slashLoc = jid.indexOf("/"); - // If there is no "@" in the JID (eg. "example.net" or "example.net/resource") - // or there are one or more "@" signs but they're all in the resourcepart (eg. "example.net/@/rp@"): - if (atCount == 0 || (atCount > 0 && slashLoc != -1 && atLoc > slashLoc)) { - localpart = ""; - finaljid = ""; - domainpartStart = 0; - } else { - final String lp = jid.substring(0, atLoc); - try { - localpart = Config.DISABLE_STRING_PREP || safe ? lp : Stringprep.nodeprep(lp); - } catch (final StringprepException e) { - throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); - } - if (localpart.isEmpty() || localpart.length() > 1023) { - throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); - } - domainpartStart = atLoc + 1; - finaljid = lp + "@"; - } - - final String dp; - if (slashCount > 0) { - final String rp = jid.substring(slashLoc + 1, jid.length()); - try { - resourcepart = Config.DISABLE_STRING_PREP || safe ? rp : Stringprep.resourceprep(rp); - } catch (final StringprepException e) { - throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); - } - if (resourcepart.isEmpty() || resourcepart.length() > 1023) { - throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); - } - try { - dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, slashLoc)), IDN.USE_STD3_ASCII_RULES); - } catch (final StringprepException e) { - throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); - } - finaljid = finaljid + dp + "/" + rp; - } else { - resourcepart = ""; - try{ - dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, jid.length())), IDN.USE_STD3_ASCII_RULES); - } catch (final StringprepException e) { - throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); - } - finaljid = finaljid + dp; - } - - // Remove trailing "." before storing the domain part. - if (dp.endsWith(".")) { - try { - domainpart = IDN.toASCII(dp.substring(0, dp.length() - 1), IDN.USE_STD3_ASCII_RULES); - } catch (final IllegalArgumentException e) { - throw new InvalidJidException(e); - } - } else { - try { - domainpart = IDN.toASCII(dp, IDN.USE_STD3_ASCII_RULES); - } catch (final IllegalArgumentException e) { - throw new InvalidJidException(e); - } - } - - // TODO: Find a proper domain validation library; validate individual parts, separators, etc. - if (domainpart.isEmpty() || domainpart.length() > 1023) { - throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); - } - - Jid.cache.put(jid, this); - - this.displayjid = finaljid; + Jid(String displayjid, String local, String domain, String resource) throws InvalidJidException { + this.displayjid = displayjid; + this.localpart = local; + this.domainpart = (null == domain) ? "" : domain; + this.resourcepart = (null == resource) ? "" : resource; } public Jid toBareJid() { try { - return resourcepart.isEmpty() ? this : fromParts(localpart, domainpart, ""); + return resourcepart.isEmpty() ? this : JidUtil.fromParts(localpart, domainpart, ""); } catch (final InvalidJidException e) { // This should never happen. throw new AssertionError("Jid " + this.toString() + " invalid"); @@ -182,7 +45,7 @@ public final class Jid { public Jid toDomainJid() { try { - return resourcepart.isEmpty() && localpart.isEmpty() ? this : fromString(getDomainpart()); + return resourcepart.isEmpty() && localpart.isEmpty() ? this : JidUtil.fromString(getDomainpart()); } catch (final InvalidJidException e) { // This should never happen. throw new AssertionError("Jid " + this.toString() + " invalid"); diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java new file mode 100644 index 00000000..433f1f4f --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java @@ -0,0 +1,145 @@ +package de.thedevstack.conversationsplus.xmpp.jid; + +import android.util.LruCache; + +import net.java.otr4j.session.SessionID; + +import java.net.IDN; + +import gnu.inet.encoding.Stringprep; +import gnu.inet.encoding.StringprepException; + +/** + */ +public class JidUtil { + private static LruCache<String,Jid> cache = new LruCache<>(1024); + + public static Jid fromSessionID(final SessionID id) throws InvalidJidException { + if (id.getUserID().isEmpty()) { + return fromString(id.getAccountID()); + } else { + return fromString(id.getAccountID()+"/"+id.getUserID()); + } + } + + public static Jid fromString(final String jid) throws InvalidJidException { + return fromString(jid, false); + } + + public static Jid fromString(final String jid, final boolean safe) throws InvalidJidException { + if (jid == null) throw new InvalidJidException(InvalidJidException.IS_NULL); + + Jid fromCache = JidUtil.cache.get(jid); + if (fromCache != null) { + return fromCache; + } + + // Hackish Android way to count the number of chars in a string... should work everywhere. + final int atCount = jid.length() - jid.replace("@", "").length(); + final int slashCount = jid.length() - jid.replace("/", "").length(); + + // Throw an error if there's anything obvious wrong with the JID... + if (jid.isEmpty() || jid.length() > 3071) { + throw new InvalidJidException(InvalidJidException.INVALID_LENGTH); + } + + // Go ahead and check if the localpart or resourcepart is empty. + if (jid.startsWith("@") || (jid.endsWith("@") && slashCount == 0) || jid.startsWith("/") || (jid.endsWith("/") && slashCount < 2)) { + throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER); + } + + String finaljid; + String localpart; + String domainpart; + String resourcepart; + + final int domainpartStart; + final int atLoc = jid.indexOf("@"); + final int slashLoc = jid.indexOf("/"); + // If there is no "@" in the JID (eg. "example.net" or "example.net/resource") + // or there are one or more "@" signs but they're all in the resourcepart (eg. "example.net/@/rp@"): + if (atCount == 0 || (atCount > 0 && slashLoc != -1 && atLoc > slashLoc)) { + localpart = ""; + finaljid = ""; + domainpartStart = 0; + } else { + final String lp = jid.substring(0, atLoc); + try { + localpart = safe ? lp : Stringprep.nodeprep(lp); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + if (localpart.isEmpty() || localpart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + domainpartStart = atLoc + 1; + finaljid = lp + "@"; + } + + final String dp; + if (slashCount > 0) { + final String rp = jid.substring(slashLoc + 1, jid.length()); + try { + resourcepart = safe ? rp : Stringprep.resourceprep(rp); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + if (resourcepart.isEmpty() || resourcepart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + try { + dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, slashLoc)), IDN.USE_STD3_ASCII_RULES); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + finaljid = finaljid + dp + "/" + rp; + } else { + resourcepart = ""; + try{ + dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, jid.length())), IDN.USE_STD3_ASCII_RULES); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + finaljid = finaljid + dp; + } + + // Remove trailing "." before storing the domain part. + if (dp.endsWith(".")) { + try { + domainpart = IDN.toASCII(dp.substring(0, dp.length() - 1), IDN.USE_STD3_ASCII_RULES); + } catch (final IllegalArgumentException e) { + throw new InvalidJidException(e); + } + } else { + try { + domainpart = IDN.toASCII(dp, IDN.USE_STD3_ASCII_RULES); + } catch (final IllegalArgumentException e) { + throw new InvalidJidException(e); + } + } + + // TODO: Find a proper domain validation library; validate individual parts, separators, etc. + if (domainpart.isEmpty() || domainpart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + + Jid createdJid = new Jid(finaljid, localpart, domainpart, resourcepart); + + JidUtil.cache.put(jid, createdJid); + + return createdJid; + } + + public static Jid fromParts(final String localpart, final String domainpart, final String resourcepart) throws InvalidJidException { + String out; + if (localpart == null || localpart.isEmpty()) { + out = domainpart; + } else { + out = localpart + "@" + domainpart; + } + if (resourcepart != null && !resourcepart.isEmpty()) { + out = out + "/" + resourcepart; + } + return JidUtil.fromString(out, false); + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/stanzas/JinglePacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/stanzas/JinglePacket.java index db771a0a..63e86c24 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/stanzas/JinglePacket.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/stanzas/JinglePacket.java @@ -51,7 +51,7 @@ public class JinglePacket extends IqPacket { } private void build() { - this.children.clear(); + this.clearChildren(); this.jingle.clearChildren(); this.jingle.setAttribute("xmlns", "urn:xmpp:jingle:1"); if (this.content != null) { @@ -60,7 +60,7 @@ public class JinglePacket extends IqPacket { if (this.reason != null) { jingle.addChild(this.reason); } - this.children.add(jingle); + this.addChild(jingle); this.setAttribute("type", "set"); } |