/* * Kontalk Java client * Copyright (C) 2016 Kontalk Devteam <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.misc; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.lang.StringUtils; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Localpart; import org.jxmpp.jid.util.JidUtil; import org.jxmpp.stringprep.XmppStringprepException; import org.jxmpp.stringprep.simple.SimpleXmppStringprep; import org.jxmpp.util.XmppStringUtils; /** * A Jabber ID (the address of an XMPP entity). Immutable. * * Escaping of local part (XEP-0106) supported. * * @author Alexander Bikadorov {@literal <[email protected]>} */ public final class JID { private static final Logger LOGGER = Logger.getLogger(JID.class.getName()); static { // good to know. For working JID validation SimpleXmppStringprep.setup(); } private final String mLocal; // escaped! private final String mDomain; private final String mResource; private final boolean mValid; private JID(String local, String domain, String resource) { mLocal = local; mDomain = domain; mResource = resource; mValid = !mLocal.isEmpty() && !mDomain.isEmpty() // NOTE: domain check could be stronger - compliant with RFC 6122, but // server does not accept most special characters // NOTE: resource not checked && JidUtil.isTypicalValidEntityBareJid( XmppStringUtils.completeJidFrom(mLocal, mDomain)); } /** Return unescaped local part. */ public String local() { return XmppStringUtils.unescapeLocalpart(mLocal); } public String domain() { return mDomain; } /** Return JID as escaped string. */ public String string() { return XmppStringUtils.completeJidFrom(mLocal, mDomain, mResource); } public String asUnescapedString() { return XmppStringUtils.completeJidFrom(this.local(), mDomain, mResource); } public boolean isValid() { return mValid; } public boolean isHash() { return mLocal.matches("[0-9a-f]{40}"); } public boolean isFull() { return !mResource.isEmpty(); } public JID toBare() { return new JID(mLocal, mDomain, ""); } /** To invalid(!) domain JID. */ public JID toDomain() { return new JID("", mDomain, ""); } public BareJid toBareSmack() { try { return JidCreate.bareFrom(this.string()); } catch (XmppStringprepException ex) { LOGGER.log(Level.WARNING, "could not convert to smack", ex); throw new RuntimeException("You didn't check isValid(), idiot!"); } } public Jid toSmack() { try { return JidCreate.from(this.string()); } catch (XmppStringprepException ex) { LOGGER.log(Level.WARNING, "could not convert to smack", ex); throw new RuntimeException("Not even a simple Jid?"); } } /** * Comparing only bare JIDs. * Case-insensitive. */ @Override public final boolean equals(Object o) { if (o == this) return true; if (!(o instanceof JID)) return false; JID oJID = (JID) o; return mLocal.equalsIgnoreCase(oJID.mLocal) && mDomain.equalsIgnoreCase(oJID.mDomain); } @Override public int hashCode() { return Objects.hash(mLocal, mDomain); } /** Use this only for debugging and otherwise string() instead! */ @Override public String toString() { return "'"+this.string()+"'"; } public static JID full(String jid) { jid = StringUtils.defaultString(jid); return escape(XmppStringUtils.parseLocalpart(jid), XmppStringUtils.parseDomain(jid), XmppStringUtils.parseResource(jid)); } public static JID bare(String jid) { jid = StringUtils.defaultString(jid); return escape(XmppStringUtils.parseLocalpart(jid), XmppStringUtils.parseDomain(jid), ""); } public static JID fromSmack(Jid jid) { Localpart localpart = jid.getLocalpartOrNull(); return new JID(localpart != null ? localpart.toString() : "", jid.getDomain().toString(), jid.getResourceOrEmpty().toString()); } public static JID bare(String local, String domain) { return escape(local, domain, ""); } private static JID escape(String local, String domain, String resource) { return new JID(XmppStringUtils.escapeLocalpart(local), domain, resource); } public static JID deleted(int id) { return new JID("", Integer.toString(id), ""); } }