aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java')
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java145
1 files changed, 145 insertions, 0 deletions
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);
+ }
+}