+ * The field is public so that our Logger could reset it if + * necessary. */ - private static String pattern = null; + public static String pattern = null; /** * Initialize a FileHandler to write to a set of files. When @@ -65,7 +69,7 @@ public class FileHandler * @param count the number of files to use * @exception IOException if there are IO problems opening the files. * @exception SecurityException if a security manager exists and if - * the caller does not have LoggingPermission("control"). + * the caller does not have LoggingPermission("control"). * @exception IllegalArgumentException if limit < 0, or count < 1. * @exception IllegalArgumentException if pattern is an empty string */ @@ -82,7 +86,7 @@ public FileHandler(String pattern, int limit, int count) *
* @exception IOException if there are IO problems opening the files. * @exception SecurityException if a security manager exists and if - * the caller does not have LoggingPermission("control")). + * the caller does not have LoggingPermission("control")). * @exception NullPointerException if pattern property is an empty String. */ public FileHandler() @@ -101,15 +105,17 @@ private static int getLimit() { if(limit == -1) { - String limitStr = - LogManager.getLogManager().getProperty(FileHandler.class.getName() + ".limit"); + String limitStr = LogManager.getLogManager().getProperty( + FileHandler.class.getName() + ".limit"); // default value limit = 0; - try { + try + { limit = Integer.parseInt(limitStr); - } catch (Exception ex) {} + } + catch (Exception ex) {} } return limit; @@ -129,10 +135,10 @@ private static String getPattern() LogManager.getLogManager().getProperty( FileHandler.class.getName() + ".pattern"); - String homeLocation = - System.getProperty("net.java.sip.communicator.SC_HOME_DIR_LOCATION"); - String dirName = - System.getProperty("net.java.sip.communicator.SC_HOME_DIR_NAME"); + String homeLocation = System.getProperty( + "net.java.sip.communicator.SC_HOME_DIR_LOCATION"); + String dirName = System.getProperty( + "net.java.sip.communicator.SC_HOME_DIR_NAME"); if(homeLocation != null && dirName != null) { @@ -164,15 +170,17 @@ private static int getCount() { if(count == -1) { - String countStr = - LogManager.getLogManager().getProperty(FileHandler.class.getName() + ".count"); + String countStr = LogManager.getLogManager().getProperty( + FileHandler.class.getName() + ".count"); // default value count = 1; - try { + try + { count = Integer.parseInt(countStr); - } catch (Exception ex) {} + } + catch (Exception ex) {} } return count; @@ -180,7 +188,8 @@ private static int getCount() /** * Creates the directory in the pattern. - * @param pattern + * + * @param pattern the directory we'd like to check. */ private static void checkDestinationDirectory(String pattern) { @@ -191,8 +200,10 @@ private static void checkDestinationDirectory(String pattern) if(ix != -1) { String dirName = pattern.substring(0, ix); - dirName = dirName.replaceAll("%h", System.getProperty("user.home")); - dirName = dirName.replaceAll("%t", System.getProperty("java.io.tmpdir")); + dirName = dirName.replaceAll( + "%h", System.getProperty("user.home")); + dirName = dirName.replaceAll( + "%t", System.getProperty("java.io.tmpdir")); new File(dirName).mkdirs(); } diff --git a/src/net/java/sip/communicator/util/IPAddressUtil.java b/src/net/java/sip/communicator/util/IPAddressUtil.java deleted file mode 100644 index e4fedeaee..000000000 --- a/src/net/java/sip/communicator/util/IPAddressUtil.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.util; - -/** - * Contains utility methods for work with IPv4 and IPv6 addresses. - *
- * TODO Rewrite to not depend on sun.net.util.IPAddressUtil. - *
- * - * @author Alan Kelly - * @author Lubomir Marinov - */ -public class IPAddressUtil - extends sun.net.util.IPAddressUtil -{ -} diff --git a/src/net/java/sip/communicator/util/Logger.java b/src/net/java/sip/communicator/util/Logger.java index 9baf45b01..d04a8f810 100644 --- a/src/net/java/sip/communicator/util/Logger.java +++ b/src/net/java/sip/communicator/util/Logger.java @@ -6,6 +6,7 @@ */ package net.java.sip.communicator.util; +import java.io.*; import java.util.logging.*; /** @@ -15,8 +16,11 @@ */ public class Logger { + /** + * The java.util.Logger that would actually be doing the logging. + */ private final java.util.logging.Logger loggerDelegate; - + /** * Base constructor * @@ -353,4 +357,25 @@ private void setLevel(java.util.logging.Level level) loggerDelegate.setLevel(level); } + + /** + * Reinitialize the logging properties and reread the logging configuration. + *+ * The same rules are used for locating the configuration properties + * as are used at startup. So if the properties containing the log dir + * locations have changed, we would read the new configuration. + */ + public void reset() + { + try + { + FileHandler.pattern = null; + LogManager.getLogManager().reset(); + LogManager.getLogManager().readConfiguration(); + } + catch (Exception e) + { + loggerDelegate.log(Level.INFO, "Failed to reinit logger.", e); + } + } } diff --git a/src/net/java/sip/communicator/util/NetworkUtils.java b/src/net/java/sip/communicator/util/NetworkUtils.java index 36fbb66da..5e3261e63 100644 --- a/src/net/java/sip/communicator/util/NetworkUtils.java +++ b/src/net/java/sip/communicator/util/NetworkUtils.java @@ -8,6 +8,7 @@ import java.net.*; import java.util.*; + import org.xbill.DNS.*; import java.text.*; @@ -43,12 +44,28 @@ public class NetworkUtils public static final String IN_ADDR_ANY = determineAnyAddress(); /** - * The maximum int value that could correspond to a port nubmer. + * The length of IPv6 addresses. + */ + private final static int IN6_ADDR_SIZE = 16; + + /** + * The size of the tokens in a String representation of IPv6 + * addresses. + */ + private final static int IN6_ADDR_TOKEN_SIZE = 2; + + /** + * The length of IPv4 addresses. + */ + private final static int IN4_ADDR_SIZE = 4; + + /** + * The maximum int value that could correspond to a port number. */ public static final int MAX_PORT_NUMBER = 65535; /** - * The minimum int value that could correspond to a port nubmer bindable + * The minimum int value that could correspond to a port number bindable * by the SIP Communicator. */ public static final int MIN_PORT_NUMBER = 1024; @@ -161,7 +178,7 @@ public static int getRandomPortNumber(int min, int max, boolean pair) */ public static boolean isIPv4Address(String address) { - return IPAddressUtil.isIPv4LiteralAddress(address); + return strToIPv4(address) != null; } /** @@ -174,7 +191,7 @@ public static boolean isIPv4Address(String address) */ public static boolean isIPv6Address(String address) { - return IPAddressUtil.isIPv6LiteralAddress(address); + return strToIPv6(address) != null; } /** @@ -195,7 +212,7 @@ public static boolean isValidIPAddress(String address) boolean ipv6Expected = false; if (address.charAt(0) == '[') { - // This is supposed to be an IPv6 litteral + // This is supposed to be an IPv6 literal if (address.length() > 2 && address.charAt(address.length() - 1) == ']') { @@ -216,11 +233,11 @@ public static boolean isValidIPAddress(String address) byte[] addr = null; // see if it is IPv4 address - addr = IPAddressUtil.textToNumericFormatV4(address); + addr = strToIPv4(address); // if not, see if it is IPv6 address if (addr == null) { - addr = IPAddressUtil.textToNumericFormatV6(address); + addr = strToIPv6(address); } // if IPv4 is found when IPv6 is expected else if (ipv6Expected) @@ -239,6 +256,256 @@ else if (ipv6Expected) return false; } + /** + * Creates a byte array containing the specified ipv4AddStr. + * + * @param ipv4AddrStr a String containing an IPv4 address. + * + * @return a byte array containing the four bytes of the address represented + * by ipv4AddrStr or null if ipv4AddrStr does not contain + * a valid IPv4 address string. + */ + public static byte[] strToIPv4(String ipv4AddrStr) + { + if (ipv4AddrStr.length() == 0) + return null; + + byte[] address = new byte[IN4_ADDR_SIZE]; + String[] tokens = ipv4AddrStr.split("\\.", -1); + long currentTkn; + try + { + switch(tokens.length) + { + case 1: + //If the address was specified as a single String we can + //directly copy it into the byte array. + currentTkn = Long.parseLong(tokens[0]); + if (currentTkn < 0 || currentTkn > 0xffffffffL) + return null; + address[0] = (byte) ((currentTkn >> 24) & 0xff); + address[1] = (byte) (((currentTkn & 0xffffff) >> 16) & 0xff); + address[2] = (byte) (((currentTkn & 0xffff) >> 8) & 0xff); + address[3] = (byte) (currentTkn & 0xff); + break; + case 2: + // If the address was passed in two parts (e.g. when dealing + // with a Class A address representation), we place the + // first one in the leftmost byte and the rest in the three + // remaining bytes of the address array. + currentTkn = Integer.parseInt(tokens[0]); + + if (currentTkn < 0 || currentTkn > 0xff) + return null; + + address[0] = (byte) (currentTkn & 0xff); + currentTkn = Integer.parseInt(tokens[1]); + + if (currentTkn < 0 || currentTkn > 0xffffff) + return null; + + address[1] = (byte) ((currentTkn >> 16) & 0xff); + address[2] = (byte) (((currentTkn & 0xffff) >> 8) &0xff); + address[3] = (byte) (currentTkn & 0xff); + break; + case 3: + // If the address was passed in three parts (e.g. when + // dealing with a Class B address representation), we place + // the first two parts in the two leftmost bytes and the + // rest in the two remaining bytes of the address array. + for (int i = 0; i < 2; i++) + { + currentTkn = Integer.parseInt(tokens[i]); + + if (currentTkn < 0 || currentTkn > 0xff) + return null; + + address[i] = (byte) (currentTkn & 0xff); + } + + currentTkn = Integer.parseInt(tokens[2]); + + if (currentTkn < 0 || currentTkn > 0xffff) + return null; + + address[2] = (byte) ((currentTkn >> 8) & 0xff); + address[3] = (byte) (currentTkn & 0xff); + break; + case 4: + // And now for the most common - four part case. This time + // there's a byte for every part :). Yuppiee! :) + for (int i = 0; i < 4; i++) + { + currentTkn = Integer.parseInt(tokens[i]); + + if (currentTkn < 0 || currentTkn > 0xff) + return null; + + address[i] = (byte) (currentTkn & 0xff); + } + break; + default: + return null; + } + } + catch(NumberFormatException e) + { + return null; + } + + return address; + } + + /** + * Creates a byte array containing the specified ipv6AddStr. + * + * @param ipv6AddrStr a String containing an IPv6 address. + * + * @return a byte array containing the four bytes of the address represented + * by ipv6AddrStr or null if ipv6AddrStr does + * not contain a valid IPv6 address string. + */ + public static byte[] strToIPv6(String ipv6AddrStr) + { + // Bail out if the string is shorter than "::" + if (ipv6AddrStr.length() < 2) + return null; + + int colonIndex; + char currentChar; + boolean sawtDigit; + int currentTkn; + char[] addrBuff = ipv6AddrStr.toCharArray(); + byte[] dst = new byte[IN6_ADDR_SIZE]; + + int srcb_length = addrBuff.length; + int scopeID = ipv6AddrStr.indexOf ("%"); + + if (scopeID == srcb_length -1) + return null; + + if (scopeID != -1) + srcb_length = scopeID; + + colonIndex = -1; + int i = 0, j = 0; + // Starting : mean we need to have at least one more. + if (addrBuff[i] == ':') + if (addrBuff[++i] != ':') + return null; + + int curtok = i; + sawtDigit = false; + currentTkn = 0; + while (i < srcb_length) + { + currentChar = addrBuff[i++]; + int chval = Character.digit(currentChar, 16); + if (chval != -1) + { + currentTkn <<= 4; + currentTkn |= chval; + if (currentTkn > 0xffff) + return null; + sawtDigit = true; + continue; + } + + if (currentChar == ':') + { + curtok = i; + + if (!sawtDigit) + { + if (colonIndex != -1) + return null; + colonIndex = j; + continue; + } + else if (i == srcb_length) + { + return null; + } + + if (j + IN6_ADDR_TOKEN_SIZE > IN6_ADDR_SIZE) + return null; + + dst[j++] = (byte) ((currentTkn >> 8) & 0xff); + dst[j++] = (byte) (currentTkn & 0xff); + sawtDigit = false; + currentTkn = 0; + continue; + } + + if (currentChar == '.' && ((j + IN4_ADDR_SIZE) <= IN6_ADDR_SIZE)) + { + String ia4 = ipv6AddrStr.substring(curtok, srcb_length); + // check this IPv4 address has 3 dots, ie. A.B.C.D + int dot_count = 0, index=0; + while ((index = ia4.indexOf ('.', index)) != -1) + { + dot_count ++; + index ++; + } + + if (dot_count != 3) + return null; + + byte[] v4addr = strToIPv4(ia4); + if (v4addr == null) + return null; + + for (int k = 0; k < IN4_ADDR_SIZE; k++) + { + dst[j++] = v4addr[k]; + } + + sawtDigit = false; + break; /* '\0' was seen by inet_pton4(). */ + } + return null; + } + + if (sawtDigit) + { + if (j + IN6_ADDR_TOKEN_SIZE > IN6_ADDR_SIZE) + return null; + + dst[j++] = (byte) ((currentTkn >> 8) & 0xff); + dst[j++] = (byte) (currentTkn & 0xff); + } + + if (colonIndex != -1) + { + int n = j - colonIndex; + + if (j == IN6_ADDR_SIZE) + return null; + + for (i = 1; i <= n; i++) + { + dst[IN6_ADDR_SIZE - i] = dst[colonIndex + n - i]; + dst[colonIndex + n - i] = 0; + } + + j = IN6_ADDR_SIZE; + } + + if (j != IN6_ADDR_SIZE) + return null; + + byte[] newdst = mappedIPv4ToRealIPv4(dst); + + if (newdst != null) + { + return newdst; + } + else + { + return dst; + } + } + /** * Returns array of hosts from the SRV record of the specified domain. * The records are ordered against the SRV record priority @@ -419,12 +686,12 @@ public static InetAddress getInetAddress(String hostAddress) byte[] addr = null; // attempt parse as IPv4 address - addr = IPAddressUtil.textToNumericFormatV4(hostAddress); + addr = strToIPv4(hostAddress); // if not IPv4, parse as IPv6 address if (addr == null) { - addr = IPAddressUtil.textToNumericFormatV6(hostAddress); + addr = strToIPv6(hostAddress); } return InetAddress.getByAddress(hostAddress, addr); } @@ -562,6 +829,57 @@ private static String determineAnyAddress() public static boolean isValidPortNumber(int port) { return MIN_PORT_NUMBER < port && port < MAX_PORT_NUMBER; + } + /** + * Returns an IPv4 address matching the one mapped in the IPv6 + * addr. Both input and returned value are in network order. + * + * @param addr a String representing an IPv4-Mapped address in textual + * format + * + * @return a byte array numerically representing the IPv4 address + */ + public static byte[] mappedIPv4ToRealIPv4(byte[] addr) + { + if (isMappedIPv4Addr(addr)) + { + byte[] newAddr = new byte[IN4_ADDR_SIZE]; + System.arraycopy(addr, 12, newAddr, 0, IN6_ADDR_SIZE); + return newAddr; + } + + return null; + } + + /** + * Utility method to check if the specified address is an IPv4 + * mapped IPv6 address. + * + * @param address the address that we'd like to determine as an IPv4 mapped + * one or not. + * + * @return true if address is an IPv4 mapped IPv6 address and + * false otherwise. + */ + private static boolean isMappedIPv4Addr(byte[] address) + { + if (address.length < IN6_ADDR_SIZE) + { + return false; + } + + if ((address[0] == 0x00) && (address[1] == 0x00) + && (address[2] == 0x00) && (address[3] == 0x00) + && (address[4] == 0x00) && (address[5] == 0x00) + && (address[6] == 0x00) && (address[7] == 0x00) + && (address[8] == 0x00) && (address[9] == 0x00) + && (address[10] == (byte)0xff) + && (address[11] == (byte)0xff)) + { + return true; + } + + return false; } } diff --git a/src/net/java/sip/communicator/util/StringUtils.java b/src/net/java/sip/communicator/util/StringUtils.java index d621b2aaf..e72a41dfc 100644 --- a/src/net/java/sip/communicator/util/StringUtils.java +++ b/src/net/java/sip/communicator/util/StringUtils.java @@ -12,6 +12,7 @@ * Utility class that helps to work with String class. * * @author Grigorii Balutsel + * @author Emil Ivov */ public final class StringUtils { @@ -28,7 +29,7 @@ private StringUtils() * with spaces between the words). * * @param camelCase a camel-case (or Pascal-case) formatted String - * from which a human-readable String is to be constructed + * from which a human-readable String is to be constructed * @return a String which represents the conversion of the specified * camel-case formatted String to a more human-readable form */ @@ -64,10 +65,10 @@ public static String convertCamelCaseToDisplayString(String camelCase) } /** - * Indicates whether string is null or empty. + * Indicates whether string is null or empty. * * @param s the string to analyze. - * @return true if string is null or empty. + * @return true if string is null or empty. */ public static boolean isNullOrEmpty(String s) { @@ -75,11 +76,11 @@ public static boolean isNullOrEmpty(String s) } /** - * Indicates whether string is null or empty. + * Indicates whether string is null or empty. * * @param s the string to analyze. * @param trim indicates whether to trim the string. - * @return true if string is null or empty. + * @return true if string is null or empty. */ public static boolean isNullOrEmpty(String s, boolean trim) { @@ -129,4 +130,49 @@ public static InputStream fromString(String string, String encoding) byte[] bytes = string.getBytes(encoding); return new ByteArrayInputStream(bytes); } + + /** + * Returns the UTF8 bytes for string and handles the unlikely case + * where UTF-8 is not supported. + * + * @param string the String whose bytes we'd like to obtain. + * + * @return string's bytes. + */ + public static byte[] getUTF8Bytes(String string) + { + try + { + return string.getBytes("UTF-8"); + } + catch(UnsupportedEncodingException exc) + { + // shouldn't happen. UTF-8 is always supported, anyways ... if + //this happens, we'll cheat + return string.getBytes(); + } + } + + /** + * Converts string into an UTF8 String and handles the + * unlikely case where UTF-8 is not supported. + * + * @param bytes the byte array that we'd like to convert into a + * String. + * + * @return the UTF-8 String. + */ + public static String getUTF8String(byte[] bytes) + { + try + { + return new String(bytes, "UTF-8"); + } + catch(UnsupportedEncodingException exc) + { + // shouldn't happen. UTF-8 is always supported, anyways ... if + //this happens, we'll cheat + return new String(bytes); + } + } } diff --git a/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java b/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java index 1de969ba1..8a00969a0 100644 --- a/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java +++ b/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java @@ -21,6 +21,9 @@ */ public class LaunchArgHandler { + /** + * Our class logger. + */ private static final net.java.sip.communicator.util.Logger logger = net.java.sip.communicator.util.Logger.getLogger(LaunchArgHandler.class); @@ -120,6 +123,9 @@ public class LaunchArgHandler */ private static LaunchArgHandler argHandler = null; + /** + * The properties where we load version info from our update location. + */ private Properties versionProperties = new Properties(); /** @@ -293,7 +299,7 @@ private void handleIPv4Enforcement() /** * Passes uriArg to our uri manager for handling. * - * @param arg the uri that we'd like to pass to + * @param uri the uri that we'd like to pass to */ private void handleUri(String uri) { @@ -305,7 +311,7 @@ private void handleUri(String uri) /** * Instructs SIP Communicator to print logging messages to the console. * - * @param the debug arg which we are not really using in this method. + * @param arg the debug arg which we are not really using in this method. */ private void handleDebugArg(String arg) { @@ -338,8 +344,9 @@ private void handleDebugArg(String arg) } /** - * Instructs SIP Communicator to allow for more than a single running - * instance. + * Instructs SIP Communicator change the location of its home dir. + * + * @param configArg the arg containing the location of the new dir. * * @return either ACTION_ERROR or ACTION_CONTINUE depending on whether or * not parsing the option went fine. @@ -366,6 +373,10 @@ private int handleConfigArg(String configArg) System.setProperty(PNAME_SC_HOME_DIR_LOCATION, configDir.getParent()); System.setProperty(PNAME_SC_HOME_DIR_NAME, configDir.getName()); + //we instantiated our class logger before we had a chance to change + //the dir so we need to reset it now. + logger.reset(); + return ACTION_CONTINUE; } @@ -426,6 +437,8 @@ private String getApplicationName() } /** * Prints an error message and then prints the help message. + * + * @param arg the unknown argument we need to print */ public void handleUnknownArg(String arg) {