| /**************************************************************************** |
| * Copyright (c) 2004 Composent, Inc. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Composent, Inc. - initial API and implementation |
| *****************************************************************************/ |
| package org.eclipse.ecf.provider.xmpp.identity; |
| |
| import java.net.URISyntaxException; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import org.eclipse.ecf.core.identity.BaseID; |
| import org.eclipse.ecf.core.identity.Namespace; |
| import org.eclipse.ecf.core.util.StringUtils; |
| import org.eclipse.ecf.internal.provider.xmpp.Messages; |
| import org.eclipse.ecf.presence.IFQID; |
| import org.eclipse.ecf.presence.im.IChatID; |
| |
| public class XMPPID extends BaseID implements IChatID, IFQID { |
| |
| private static final long serialVersionUID = 3257289140701049140L; |
| public static final char USER_HOST_DELIMITER = '@'; |
| public static final char PORT_DELIMITER = ':'; |
| public static final String PATH_DELIMITER = "/"; |
| |
| static class XMPPEscape { |
| StringBuffer buf = new StringBuffer(); |
| |
| public XMPPEscape(char[] chars) { |
| if (chars != null) { |
| for (int i = 0; i < chars.length; i++) { |
| buf.append(chars[i]); |
| } |
| } |
| } |
| |
| public String getAsString() { |
| return buf.toString(); |
| } |
| |
| } |
| |
| protected static Hashtable escapeTable; |
| |
| static { |
| escapeTable = new Hashtable(10); |
| escapeTable.put("@", new XMPPEscape(new char[] { '\\', '4', '0' })); |
| escapeTable.put("\"", new XMPPEscape(new char[] { '\\', '2', '2' })); |
| escapeTable.put("&", new XMPPEscape(new char[] { '\\', '2', '6' })); |
| escapeTable.put("'", new XMPPEscape(new char[] { '\\', '2', '7' })); |
| escapeTable.put("/", new XMPPEscape(new char[] { '\\', '2', 'f' })); |
| escapeTable.put(":", new XMPPEscape(new char[] { '\\', '3', 'a' })); |
| escapeTable.put("<", new XMPPEscape(new char[] { '\\', '3', 'c' })); |
| escapeTable.put(">", new XMPPEscape(new char[] { '\\', '3', 'e' })); |
| escapeTable.put("\\", new XMPPEscape(new char[] { '\\', '5', 'c' })); |
| } |
| |
| // implements JEP-0106 JID escaping: |
| // http://www.xmpp.org/extensions/xep-0106.html |
| static String fixEscapeInNode(String node) { |
| if (node == null) |
| return null; |
| for (final Iterator i = escapeTable.keySet().iterator(); i.hasNext();) { |
| final String key = (String) i.next(); |
| final XMPPEscape escape = (XMPPEscape) escapeTable.get(key); |
| node = StringUtils.replaceAll(node, key, escape.getAsString()); |
| } |
| return node; |
| } |
| |
| static String fixPercentEscape(String src) { |
| if (src == null) |
| return null; |
| return StringUtils.replaceAll(src, "%", "%25"); |
| } |
| |
| public static String unfixEscapeInNode(String node) { |
| if (node == null) |
| return null; |
| for (final Iterator i = escapeTable.keySet().iterator(); i.hasNext();) { |
| final String key = (String) i.next(); |
| final XMPPEscape escape = (XMPPEscape) escapeTable.get(key); |
| node = StringUtils.replaceAll(node, escape.getAsString(), key); |
| } |
| return node; |
| } |
| |
| protected String username; |
| protected String hostname; |
| protected String resourcename; |
| protected int port = -1; |
| |
| public XMPPID(Namespace namespace, String unamehost) |
| throws URISyntaxException { |
| super(namespace); |
| unamehost = fixPercentEscape(unamehost); |
| if (unamehost == null) |
| throw new URISyntaxException(unamehost, |
| Messages.XMPPID_EXCEPTION_XMPPID_USERNAME_NOT_NULL); |
| // Handle parsing of user@host/resource string |
| int atIndex = unamehost.lastIndexOf(USER_HOST_DELIMITER); |
| if (atIndex == -1) |
| throw new URISyntaxException(unamehost, |
| Messages.XMPPID_EXCEPTION_HOST_PORT_NOT_VALID); |
| username = fixEscapeInNode(unamehost.substring(0, atIndex)); |
| final String remainder = unamehost.substring(atIndex + 1); |
| // Handle parsing of host:port |
| atIndex = remainder.lastIndexOf(PORT_DELIMITER); |
| if (atIndex != -1) { |
| try { |
| final int slashLoc = remainder.indexOf(PATH_DELIMITER); |
| if (slashLoc != -1) |
| port = Integer.parseInt(remainder.substring(atIndex + 1, |
| slashLoc)); |
| else |
| port = Integer.parseInt(remainder.substring(atIndex + 1)); |
| } catch (final NumberFormatException e) { |
| throw new URISyntaxException(unamehost, |
| Messages.XMPPID_EXCEPTION_INVALID_PORT); |
| } |
| hostname = remainder.substring(0, atIndex); |
| } |
| atIndex = remainder.indexOf(PATH_DELIMITER); |
| if (atIndex != -1) { |
| if (hostname == null) |
| hostname = remainder.substring(0, atIndex); |
| setResourceName(remainder.substring(atIndex + 1)); |
| } else { |
| setResourceName(null); |
| } |
| if (hostname == null) |
| hostname = remainder; |
| } |
| |
| protected int namespaceCompareTo(BaseID o) { |
| return getName().compareTo(o.getName()); |
| } |
| |
| protected boolean namespaceEquals(BaseID o) { |
| if (!(o instanceof XMPPID)) { |
| return false; |
| } |
| final XMPPID other = (XMPPID) o; |
| // Get resources from this and other |
| String thisResourceName = getResourceName(); |
| String otherResourceName = other.getResourceName(); |
| // The resources are considered equal if either one is null (not known |
| // yet), or they are equal by |
| // string comparison |
| boolean resourceEquals = false; |
| if (thisResourceName == null) { |
| resourceEquals = (otherResourceName == null) ? true : false; |
| } else { |
| resourceEquals = thisResourceName.equals(otherResourceName); |
| } |
| return resourceEquals |
| && getUsernameAtHost().equals(other.getUsernameAtHost()); |
| } |
| |
| protected String namespaceGetName() { |
| return getUsernameAtHost(); |
| } |
| |
| protected int namespaceHashCode() { |
| return getUsernameAtHost().hashCode(); |
| } |
| |
| public String getNodename() { |
| return username; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.identity.BaseID#namespaceToExternalForm() |
| */ |
| protected String namespaceToExternalForm() { |
| return getNamespace().getScheme() + "://" + getFQName(); |
| } |
| |
| public String getUsername() { |
| return unfixEscapeInNode(username); |
| } |
| |
| public String getHostname() { |
| return hostname; |
| } |
| |
| public String getResourceName() { |
| return resourcename; |
| } |
| |
| public void setResourceName(String resourceName) { |
| this.resourcename = resourceName; |
| } |
| |
| public int getPort() { |
| return port; |
| } |
| |
| public String getUsernameAtHost() { |
| String username = getUsername(); |
| String hostname = getHostname(); |
| int semiColonIdx = hostname.indexOf(';'); |
| if (semiColonIdx != -1) { |
| hostname = hostname.substring(0, semiColonIdx); |
| } |
| return username + USER_HOST_DELIMITER + hostname |
| + ((getPort() == -1) ? "" : ":" + getPort()); |
| } |
| |
| public String getFQName() { |
| String rn = getResourceName(); |
| return getUsernameAtHost() + PATH_DELIMITER + ((rn == null) ? "" : rn); |
| } |
| |
| public String toString() { |
| final StringBuffer sb = new StringBuffer("XMPPID["); //$NON-NLS-1$ |
| sb.append(toExternalForm()).append("]"); |
| return sb.toString(); |
| } |
| |
| public Object getAdapter(Class clazz) { |
| if (clazz.isInstance(this)) { |
| return this; |
| } else |
| return super.getAdapter(clazz); |
| } |
| } |