diff --git a/src/com/beetstra/jutf7/Base64Util.java b/src/com/beetstra/jutf7/Base64Util.java deleted file mode 100644 index 6dffb32c5..000000000 --- a/src/com/beetstra/jutf7/Base64Util.java +++ /dev/null @@ -1,117 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2006 J.T. Beetstra - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -package com.beetstra.jutf7; - -import java.util.Arrays; - -/** - *

- * Represent a base 64 mapping. The 64 characters used in the encoding can be - * specified, since modified-UTF-7 uses other characters than UTF-7 (',' instead - * of '/'). - *

- *

- * The exact type of the arguments and result values is adapted to the needs of - * the encoder and decoder, as opposed to following a strict interpretation of - * base 64. - *

- *

- * Base 64, as specified in RFC 2045, is an encoding used to encode bytes as - * characters. In (modified-)UTF-7 however, it is used to encode characters as - * bytes, using some intermediate steps: - *

- *
    - *
  1. Encode all characters as a 16-bit (UTF-16) integer value
  2. - *
  3. Write this as stream of bytes (most-significant first)
  4. - *
  5. Encode these bytes using (modified) base 64 encoding
  6. - *
  7. Write the thus formed stream of characters as a stream of bytes, using - * ASCII encoding
  8. - *
- * - * @author Jaap Beetstra - */ -class Base64Util { - private static final int ALPHABET_LENGTH = 64; - private final char[] alphabet; - private final int[] inverseAlphabet; - - /** - * Initializes the class with the specified encoding/decoding alphabet. - * - * @param alphabet - * @throws IllegalArgumentException if alphabet is not 64 characters long or - * contains characters which are not 7-bit ASCII - */ - Base64Util(final String alphabet) { - this.alphabet = alphabet.toCharArray(); - if (alphabet.length() != ALPHABET_LENGTH) - throw new IllegalArgumentException("alphabet has incorrect length (should be 64, not " - + alphabet.length() + ")"); - inverseAlphabet = new int[128]; - Arrays.fill(inverseAlphabet, -1); - for (int i = 0; i < this.alphabet.length; i++) { - final char ch = this.alphabet[i]; - if (ch >= 128) - throw new IllegalArgumentException("invalid character in alphabet: " + ch); - inverseAlphabet[ch] = i; - } - } - - /** - * Returns the integer value of the six bits represented by the specified - * character. - * - * @param ch The character, as a ASCII encoded byte - * @return The six bits, as an integer value, or -1 if the byte is not in - * the alphabet - */ - int getSextet(final byte ch) { - if (ch >= 128) - return -1; - return inverseAlphabet[ch]; - } - - /** - * Tells whether the alphabet contains the specified character. - * - * @param ch The character - * @return true if the alphabet contains ch, false otherwise - */ - boolean contains(final char ch) { - if (ch >= 128) - return false; - return inverseAlphabet[ch] >= 0; - } - - /** - * Encodes the six bit group as a character. - * - * @param sextet The six bit group to be encoded - * @return The ASCII value of the character - */ - byte getChar(final int sextet) { - return (byte)alphabet[sextet]; - } -} diff --git a/src/com/beetstra/jutf7/CharsetProvider.java b/src/com/beetstra/jutf7/CharsetProvider.java deleted file mode 100644 index f0cabe562..000000000 --- a/src/com/beetstra/jutf7/CharsetProvider.java +++ /dev/null @@ -1,90 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2006 J.T. Beetstra - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -package com.beetstra.jutf7; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -/** - *

- * Charset service-provider class used for both variants of the UTF-7 charset - * and the modified-UTF-7 charset. - *

- * - * @author Jaap Beetstra - */ -public class CharsetProvider extends java.nio.charset.spi.CharsetProvider { - private static final String UTF7_NAME = "UTF-7"; - private static final String UTF7_O_NAME = "X-UTF-7-OPTIONAL"; - private static final String UTF7_M_NAME = "X-MODIFIED-UTF-7"; - private static final String[] UTF7_ALIASES = new String[] { - "UNICODE-1-1-UTF-7", "CSUNICODE11UTF7", "X-RFC2152", "X-RFC-2152" - }; - private static final String[] UTF7_O_ALIASES = new String[] { - "X-RFC2152-OPTIONAL", "X-RFC-2152-OPTIONAL" - }; - private static final String[] UTF7_M_ALIASES = new String[] { - "X-IMAP-MODIFIED-UTF-7", "X-IMAP4-MODIFIED-UTF7", "X-IMAP4-MODIFIED-UTF-7", - "X-RFC3501", "X-RFC-3501" - }; - private Charset utf7charset = new UTF7Charset(UTF7_NAME, UTF7_ALIASES, false); - private Charset utf7oCharset = new UTF7Charset(UTF7_O_NAME, UTF7_O_ALIASES, true); - private Charset imap4charset = new ModifiedUTF7Charset(UTF7_M_NAME, UTF7_M_ALIASES); - private List charsets; - - public CharsetProvider() { - charsets = Arrays.asList(new Object[] { - utf7charset, imap4charset, utf7oCharset - }); - } - - /** - * {@inheritDoc} - */ - public Charset charsetForName(String charsetName) { - charsetName = charsetName.toUpperCase(); - for (Iterator iter = charsets.iterator(); iter.hasNext();) { - Charset charset = (Charset)iter.next(); - if (charset.name().equals(charsetName)) - return charset; - } - for (Iterator iter = charsets.iterator(); iter.hasNext();) { - Charset charset = (Charset)iter.next(); - if (charset.aliases().contains(charsetName)) - return charset; - } - return null; - } - - /** - * {@inheritDoc} - */ - public Iterator charsets() { - return charsets.iterator(); - } -} diff --git a/src/com/beetstra/jutf7/ModifiedUTF7Charset.java b/src/com/beetstra/jutf7/ModifiedUTF7Charset.java deleted file mode 100644 index 603a19ee9..000000000 --- a/src/com/beetstra/jutf7/ModifiedUTF7Charset.java +++ /dev/null @@ -1,57 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2006 J.T. Beetstra - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -package com.beetstra.jutf7; - -/** - *

- * The character set specified in RFC 3501 to use for IMAP4rev1 mailbox name - * encoding. - *

- * - * @see RFC 3501< /a> - * @author Jaap Beetstra - */ -class ModifiedUTF7Charset extends UTF7StyleCharset { - private static final String MODIFIED_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - + "abcdefghijklmnopqrstuvwxyz" + "0123456789+,"; - - ModifiedUTF7Charset(String name, String[] aliases) { - super(name, aliases, MODIFIED_BASE64_ALPHABET, true); - } - - boolean canEncodeDirectly(char ch) { - if (ch == shift()) - return false; - return ch >= 0x20 && ch <= 0x7E; - } - - byte shift() { - return '&'; - } - - byte unshift() { - return '-'; - } -} diff --git a/src/com/beetstra/jutf7/UTF7Charset.java b/src/com/beetstra/jutf7/UTF7Charset.java deleted file mode 100644 index 8c85472cf..000000000 --- a/src/com/beetstra/jutf7/UTF7Charset.java +++ /dev/null @@ -1,75 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2006 J.T. Beetstra - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -package com.beetstra.jutf7; - -/** - *

- * The character set specified in RFC 2152. Two variants are supported using the - * encodeOptional constructor flag - *

- * - * @see
RFC 2152< /a> - * @author Jaap Beetstra - */ -class UTF7Charset extends UTF7StyleCharset { - private static final String BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; - private static final String SET_D = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?"; - private static final String SET_O = "!\"#$%&*;<=>@[]^_`{|}"; - private static final String RULE_3 = " \t\r\n"; - final String directlyEncoded; - - UTF7Charset(String name, String[] aliases, boolean includeOptional) { - super(name, aliases, BASE64_ALPHABET, false); - if (includeOptional) - this.directlyEncoded = SET_D + SET_O + RULE_3; - else - this.directlyEncoded = SET_D + RULE_3; - } - - /* - * (non-Javadoc) - * @see com.beetstra.jutf7.UTF7StyleCharset#canEncodeDirectly(char) - */ - boolean canEncodeDirectly(char ch) { - return directlyEncoded.indexOf(ch) >= 0; - } - - /* - * (non-Javadoc) - * @see com.beetstra.jutf7.UTF7StyleCharset#shift() - */ - byte shift() { - return '+'; - } - - /* - * (non-Javadoc) - * @see com.beetstra.jutf7.UTF7StyleCharset#unshift() - */ - byte unshift() { - return '-'; - } -} diff --git a/src/com/beetstra/jutf7/UTF7StyleCharset.java b/src/com/beetstra/jutf7/UTF7StyleCharset.java deleted file mode 100644 index 0878af603..000000000 --- a/src/com/beetstra/jutf7/UTF7StyleCharset.java +++ /dev/null @@ -1,117 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2006 J.T. Beetstra - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -package com.beetstra.jutf7; - -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.util.Arrays; -import java.util.List; - -/** - *

- * Abstract base class for UTF-7 style encoding and decoding. - *

- * - * @author Jaap Beetstra - */ -abstract class UTF7StyleCharset extends Charset { - private static final List CONTAINED = Arrays.asList(new String[] { - "US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16", "UTF-16LE", "UTF-16BE" - }); - final boolean strict; - Base64Util base64; - - /** - *

- * Besides the name and aliases, two additional parameters are required. - * First the base 64 alphabet used; in modified UTF-7 a slightly different - * alphabet is used. Additionally, it should be specified if encoders and - * decoders should be strict about the interpretation of malformed encoded - * sequences. This is used since modified UTF-7 specifically disallows some - * constructs which are allowed (or not specifically disallowed) in UTF-7 - * (RFC 2152). - *

- * - * @param canonicalName The name as defined in java.nio.charset.Charset - * @param aliases The aliases as defined in java.nio.charset.Charset - * @param alphabet The base 64 alphabet used - * @param strict True if strict handling of sequences is requested - */ - protected UTF7StyleCharset(String canonicalName, String[] aliases, String alphabet, - boolean strict) { - super(canonicalName, aliases); - this.base64 = new Base64Util(alphabet); - this.strict = strict; - } - - /* - * (non-Javadoc) - * @see java.nio.charset.Charset#contains(java.nio.charset.Charset) - */ - public boolean contains(final Charset cs) { - return CONTAINED.contains(cs.name()); - } - - /* - * (non-Javadoc) - * @see java.nio.charset.Charset#newDecoder() - */ - public CharsetDecoder newDecoder() { - return new UTF7StyleCharsetDecoder(this, base64, strict); - } - - /* - * (non-Javadoc) - * @see java.nio.charset.Charset#newEncoder() - */ - public CharsetEncoder newEncoder() { - return new UTF7StyleCharsetEncoder(this, base64, strict); - } - - /** - * Tells if a character can be encoded using simple (US-ASCII) encoding or - * requires base 64 encoding. - * - * @param ch The character - * @return True if the character can be encoded directly, false otherwise - */ - abstract boolean canEncodeDirectly(char ch); - - /** - * Returns character used to switch to base 64 encoding. - * - * @return The shift character - */ - abstract byte shift(); - - /** - * Returns character used to switch from base 64 encoding to simple - * encoding. - * - * @return The unshift character - */ - abstract byte unshift(); -} diff --git a/src/com/beetstra/jutf7/UTF7StyleCharsetDecoder.java b/src/com/beetstra/jutf7/UTF7StyleCharsetDecoder.java deleted file mode 100644 index 2fa9d3435..000000000 --- a/src/com/beetstra/jutf7/UTF7StyleCharsetDecoder.java +++ /dev/null @@ -1,195 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2006 J.T. Beetstra - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -package com.beetstra.jutf7; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; - -/** - *

- * The CharsetDecoder used to decode both variants of the UTF-7 charset and the - * modified-UTF-7 charset. - *

- * - * @author Jaap Beetstra - */ -class UTF7StyleCharsetDecoder extends CharsetDecoder { - private final Base64Util base64; - private final byte shift; - private final byte unshift; - private final boolean strict; - private boolean base64mode; - private int bitsRead; - private int tempChar; - private boolean justShifted; - private boolean justUnshifted; - - UTF7StyleCharsetDecoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) { - super(cs, 0.6f, 1.0f); - this.base64 = base64; - this.strict = strict; - this.shift = cs.shift(); - this.unshift = cs.unshift(); - } - - /* - * (non-Javadoc) - * @see java.nio.charset.CharsetDecoder#decodeLoop(java.nio.ByteBuffer, - * java.nio.CharBuffer) - */ - protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { - while (in.hasRemaining()) { - byte b = in.get(); - if (base64mode) { - if (b == unshift) { - if (base64bitsWaiting()) - return malformed(in); - if (justShifted) { - if (!out.hasRemaining()) - return overflow(in); - out.put((char)shift); - } else - justUnshifted = true; - setUnshifted(); - } else { - if (!out.hasRemaining()) - return overflow(in); - CoderResult result = handleBase64(in, out, b); - if (result != null) - return result; - } - justShifted = false; - } else { - if (b == shift) { - base64mode = true; - if (justUnshifted && strict) - return malformed(in); - justShifted = true; - continue; - } - if (!out.hasRemaining()) - return overflow(in); - out.put((char)b); - justUnshifted = false; - } - } - return CoderResult.UNDERFLOW; - } - - private CoderResult overflow(ByteBuffer in) { - in.position(in.position() - 1); - return CoderResult.OVERFLOW; - } - - /** - *

- * Decodes a byte in base 64 mode. Will directly write a character to - * the output buffer if completed. - *

- * - * @param in The input buffer - * @param out The output buffer - * @param lastRead Last byte read from the input buffer - * @return CoderResult.malformed if a non-base 64 character was encountered - * in strict mode, null otherwise - */ - private CoderResult handleBase64(ByteBuffer in, CharBuffer out, byte lastRead) { - CoderResult result = null; - int sextet = base64.getSextet(lastRead); - if (sextet >= 0) { - bitsRead += 6; - if (bitsRead < 16) { - tempChar += sextet << (16 - bitsRead); - } else { - bitsRead -= 16; - tempChar += sextet >> (bitsRead); - out.put((char)tempChar); - tempChar = (sextet << (16 - bitsRead)) & 0xFFFF; - } - } else { - if (strict) - return malformed(in); - out.put((char)lastRead); - if (base64bitsWaiting()) - result = malformed(in); - setUnshifted(); - } - return result; - } - - /* - * (non-Javadoc) - * @see java.nio.charset.CharsetDecoder#implFlush(java.nio.CharBuffer) - */ - protected CoderResult implFlush(CharBuffer out) { - if ((base64mode && strict) || base64bitsWaiting()) - return CoderResult.malformedForLength(1); - return CoderResult.UNDERFLOW; - } - - /* - * (non-Javadoc) - * @see java.nio.charset.CharsetDecoder#implReset() - */ - protected void implReset() { - setUnshifted(); - justUnshifted = false; - } - - /** - *

- * Resets the input buffer position to just before the last byte read, and - * returns a result indicating to skip the last byte. - *

- * - * @param in The input buffer - * @return CoderResult.malformedForLength(1); - */ - private CoderResult malformed(ByteBuffer in) { - in.position(in.position() - 1); - return CoderResult.malformedForLength(1); - } - - /** - * @return True if there are base64 encoded characters waiting to be written - */ - private boolean base64bitsWaiting() { - return tempChar != 0 || bitsRead >= 6; - } - - /** - *

- * Updates internal state to reflect the decoder is no longer in base 64 - * mode - *

- */ - private void setUnshifted() { - base64mode = false; - bitsRead = 0; - tempChar = 0; - } -} diff --git a/src/com/beetstra/jutf7/UTF7StyleCharsetEncoder.java b/src/com/beetstra/jutf7/UTF7StyleCharsetEncoder.java deleted file mode 100644 index de8239713..000000000 --- a/src/com/beetstra/jutf7/UTF7StyleCharsetEncoder.java +++ /dev/null @@ -1,217 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2006 J.T. Beetstra - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -package com.beetstra.jutf7; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; - -/** - *

- * The CharsetEncoder used to encode both variants of the UTF-7 charset and the - * modified-UTF-7 charset. - *

- *

- * Please note this class does not behave strictly according to the - * specification in Sun Java VMs before 1.6. This is done to get around - * a bug in the implementation of - * {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)}. Unfortunately, - * that method cannot be overridden. - *

- * - * @see
JDK - * bug 6221056< /a> - * @author Jaap Beetstra - */ -class UTF7StyleCharsetEncoder extends CharsetEncoder { - private static final float AVG_BYTES_PER_CHAR = 1.5f; - private static final float MAX_BYTES_PER_CHAR = 5.0f; - private final UTF7StyleCharset cs; - private final Base64Util base64; - private final byte shift; - private final byte unshift; - private final boolean strict; - private boolean base64mode; - private int bitsToOutput; - private int sextet; - static boolean useUglyHackToForceCallToFlushInJava5; - static { - String version = System.getProperty("java.specification.version"); - String vendor = System.getProperty("java.vm.vendor"); - useUglyHackToForceCallToFlushInJava5 = "1.4".equals(version) || "1.5".equals(version); - useUglyHackToForceCallToFlushInJava5 &= "Sun Microsystems Inc.".equals(vendor); - } - - UTF7StyleCharsetEncoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) { - super(cs, AVG_BYTES_PER_CHAR, MAX_BYTES_PER_CHAR); - this.cs = cs; - this.base64 = base64; - this.strict = strict; - this.shift = cs.shift(); - this.unshift = cs.unshift(); - } - - /* - * (non-Javadoc) - * @see java.nio.charset.CharsetEncoder#implReset() - */ - protected void implReset() { - base64mode = false; - sextet = 0; - bitsToOutput = 0; - } - - /** - * {@inheritDoc} - *

- * Note that this method might return CoderResult.OVERFLOW (as - * is required by the specification) if insufficient space is available in - * the output buffer. However, calling it again on JDKs before Java 6 - * triggers a bug in - * {@link java.nio.charset.CharsetEncoder#flush(ByteBuffer)} causing it to - * throw an IllegalStateException (the buggy method is final, - * thus cannot be overridden). - *

- * - * @see
- * JDK bug 6227608< /a> - * @param out The output byte buffer - * @return A coder-result object describing the reason for termination - */ - protected CoderResult implFlush(ByteBuffer out) { - if (base64mode) { - if (out.remaining() < 2) - return CoderResult.OVERFLOW; - if (bitsToOutput != 0) - out.put(base64.getChar(sextet)); - out.put(unshift); - } - return CoderResult.UNDERFLOW; - } - - /** - * {@inheritDoc} - *

- * Note that this method might return CoderResult.OVERFLOW, - * even though there is sufficient space available in the output buffer. - * This is done to force the broken implementation of - * {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)} to call flush - * (the buggy method is final, thus cannot be overridden). - *

- *

- * However, String.getBytes() fails if CoderResult.OVERFLOW is returned, - * since this assumes it always allocates sufficient bytes (maxBytesPerChar - * * nr_of_chars). Thus, as an extra check, the size of the input buffer is - * compared against the size of the output buffer. A static variable is used - * to indicate if a broken java version is used. - *

- *

- * It is not possible to directly write the last few bytes, since more bytes - * might be waiting to be encoded then those available in the input buffer. - *

- * - * @see
- * JDK bug 6221056< /a> - * @param in The input character buffer - * @param out The output byte buffer - * @return A coder-result object describing the reason for termination - */ - protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { - while (in.hasRemaining()) { - if (out.remaining() < 4) - return CoderResult.OVERFLOW; - char ch = in.get(); - if (cs.canEncodeDirectly(ch)) { - unshift(out, ch); - out.put((byte)ch); - } else if (!base64mode && ch == shift) { - out.put(shift); - out.put(unshift); - } else - encodeBase64(ch, out); - } - /* - * These lines are required to trick JDK 1.5 and - * earlier into flushing when using Charset.encode(String), - * Charset.encode(CharBuffer) or CharsetEncoder.encode(CharBuffer) - * Without them, the last few bytes may be missing. - */ - if (base64mode && useUglyHackToForceCallToFlushInJava5 - && out.limit() != MAX_BYTES_PER_CHAR * in.limit()) - return CoderResult.OVERFLOW; - /* */ - return CoderResult.UNDERFLOW; - } - - /** - *

- * Writes the bytes necessary to leave base 64 mode. This might - * include an unshift character. - *

- * - * @param out - * @param ch - */ - private void unshift(ByteBuffer out, char ch) { - if (!base64mode) - return; - if (bitsToOutput != 0) - out.put(base64.getChar(sextet)); - if (base64.contains(ch) || ch == unshift || strict) - out.put(unshift); - base64mode = false; - sextet = 0; - bitsToOutput = 0; - } - - /** - *

- * Writes the bytes necessary to encode a character in base 64 mode. - * All bytes which are fully determined will be written. The fields - * bitsToOutput and sextet are used to remember - * the bytes not yet fully determined. - *

- * - * @param out - * @param ch - */ - private void encodeBase64(char ch, ByteBuffer out) { - if (!base64mode) - out.put(shift); - base64mode = true; - bitsToOutput += 16; - while (bitsToOutput >= 6) { - bitsToOutput -= 6; - sextet += (ch >> bitsToOutput); - sextet &= 0x3F; - out.put(base64.getChar(sextet)); - sextet = 0; - } - sextet = (ch << (6 - bitsToOutput)) & 0x3F; - } -} diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java deleted file mode 100644 index 013489b9a..000000000 --- a/src/com/fsck/k9/Account.java +++ /dev/null @@ -1,372 +0,0 @@ - -package com.fsck.k9; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.UUID; - -import android.content.Context; -import android.content.SharedPreferences; -import android.net.Uri; - -/** - * Account stores all of the settings for a single account defined by the user. It is able to save - * and delete itself given a Preferences to work with. Each account is defined by a UUID. - */ -public class Account implements Serializable { - public static final int DELETE_POLICY_NEVER = 0; - public static final int DELETE_POLICY_7DAYS = 1; - public static final int DELETE_POLICY_ON_DELETE = 2; - - private static final long serialVersionUID = 2975156672298625121L; - - String mUuid; - String mStoreUri; - String mLocalStoreUri; - String mTransportUri; - String mDescription; - String mName; - String mEmail; - String mSignature; - String mAlwaysBcc; - int mAutomaticCheckIntervalMinutes; - long mLastAutomaticCheckTime; - boolean mNotifyNewMail; - String mDraftsFolderName; - String mSentFolderName; - String mTrashFolderName; - String mOutboxFolderName; - int mAccountNumber; - boolean mVibrate; - String mRingtoneUri; - - /** - *
-     * 0 Never 
-     * 1 After 7 days 
-     * 2 When I delete from inbox
-     * 
- */ - int mDeletePolicy; - - public Account(Context context) { - // TODO Change local store path to something readable / recognizable - mUuid = UUID.randomUUID().toString(); - mLocalStoreUri = "local://localhost/" + context.getDatabasePath(mUuid + ".db"); - mAutomaticCheckIntervalMinutes = -1; - mAccountNumber = -1; - mNotifyNewMail = true; - mSignature = "Sent from my Android phone with K-9. Please excuse my brevity."; - mVibrate = false; - mRingtoneUri = "content://settings/system/notification_sound"; - } - - Account(Preferences preferences, String uuid) { - this.mUuid = uuid; - refresh(preferences); - } - - /** - * Refresh the account from the stored settings. - */ - public void refresh(Preferences preferences) { - mStoreUri = Utility.base64Decode(preferences.mSharedPreferences.getString(mUuid - + ".storeUri", null)); - mLocalStoreUri = preferences.mSharedPreferences.getString(mUuid + ".localStoreUri", null); - mTransportUri = Utility.base64Decode(preferences.mSharedPreferences.getString(mUuid - + ".transportUri", null)); - mDescription = preferences.mSharedPreferences.getString(mUuid + ".description", null); - mAlwaysBcc = preferences.mSharedPreferences.getString(mUuid + ".alwaysBcc", mAlwaysBcc); - mName = preferences.mSharedPreferences.getString(mUuid + ".name", mName); - mEmail = preferences.mSharedPreferences.getString(mUuid + ".email", mEmail); - mSignature = preferences.mSharedPreferences.getString(mUuid + ".signature", mSignature); - mAutomaticCheckIntervalMinutes = preferences.mSharedPreferences.getInt(mUuid - + ".automaticCheckIntervalMinutes", -1); - mLastAutomaticCheckTime = preferences.mSharedPreferences.getLong(mUuid - + ".lastAutomaticCheckTime", 0); - mNotifyNewMail = preferences.mSharedPreferences.getBoolean(mUuid + ".notifyNewMail", - false); - mDeletePolicy = preferences.mSharedPreferences.getInt(mUuid + ".deletePolicy", 0); - mDraftsFolderName = preferences.mSharedPreferences.getString(mUuid + ".draftsFolderName", - "Drafts"); - mSentFolderName = preferences.mSharedPreferences.getString(mUuid + ".sentFolderName", - "Sent"); - mTrashFolderName = preferences.mSharedPreferences.getString(mUuid + ".trashFolderName", - "Trash"); - mOutboxFolderName = preferences.mSharedPreferences.getString(mUuid + ".outboxFolderName", - "Outbox"); - mAccountNumber = preferences.mSharedPreferences.getInt(mUuid + ".accountNumber", 0); - mVibrate = preferences.mSharedPreferences.getBoolean(mUuid + ".vibrate", false); - mRingtoneUri = preferences.mSharedPreferences.getString(mUuid + ".ringtone", - "content://settings/system/notification_sound"); - } - - public String getUuid() { - return mUuid; - } - - public String getStoreUri() { - return mStoreUri; - } - - public void setStoreUri(String storeUri) { - this.mStoreUri = storeUri; - } - - public String getTransportUri() { - return mTransportUri; - } - - public void setTransportUri(String transportUri) { - this.mTransportUri = transportUri; - } - - public String getDescription() { - return mDescription; - } - - public void setDescription(String description) { - this.mDescription = description; - } - - public String getName() { - return mName; - } - - public void setName(String name) { - this.mName = name; - } - - public String getSignature() { - return mSignature; - } - - public void setSignature(String signature) { - this.mSignature = signature; - } - - public String getEmail() { - return mEmail; - } - - public void setEmail(String email) { - this.mEmail = email; - } - - public String getAlwaysBcc() { - return mAlwaysBcc; - } - - public void setAlwaysBcc(String alwaysBcc) { - this.mAlwaysBcc = alwaysBcc; - } - - - public boolean isVibrate() { - return mVibrate; - } - - public void setVibrate(boolean vibrate) { - mVibrate = vibrate; - } - - public String getRingtone() { - return mRingtoneUri; - } - - public void setRingtone(String ringtoneUri) { - mRingtoneUri = ringtoneUri; - } - - public void delete(Preferences preferences) { - String[] uuids = preferences.mSharedPreferences.getString("accountUuids", "").split(","); - StringBuffer sb = new StringBuffer(); - for (int i = 0, length = uuids.length; i < length; i++) { - if (!uuids[i].equals(mUuid)) { - if (sb.length() > 0) { - sb.append(','); - } - sb.append(uuids[i]); - } - } - String accountUuids = sb.toString(); - SharedPreferences.Editor editor = preferences.mSharedPreferences.edit(); - editor.putString("accountUuids", accountUuids); - - editor.remove(mUuid + ".storeUri"); - editor.remove(mUuid + ".localStoreUri"); - editor.remove(mUuid + ".transportUri"); - editor.remove(mUuid + ".description"); - editor.remove(mUuid + ".name"); - editor.remove(mUuid + ".email"); - editor.remove(mUuid + ".alwaysBcc"); - editor.remove(mUuid + ".automaticCheckIntervalMinutes"); - editor.remove(mUuid + ".lastAutomaticCheckTime"); - editor.remove(mUuid + ".notifyNewMail"); - editor.remove(mUuid + ".deletePolicy"); - editor.remove(mUuid + ".draftsFolderName"); - editor.remove(mUuid + ".sentFolderName"); - editor.remove(mUuid + ".trashFolderName"); - editor.remove(mUuid + ".outboxFolderName"); - editor.remove(mUuid + ".accountNumber"); - editor.remove(mUuid + ".vibrate"); - editor.remove(mUuid + ".ringtone"); - editor.commit(); - } - - public void save(Preferences preferences) { - if (!preferences.mSharedPreferences.getString("accountUuids", "").contains(mUuid)) { - /* - * When the account is first created we assign it a unique account number. The - * account number will be unique to that account for the lifetime of the account. - * So, we get all the existing account numbers, sort them ascending, loop through - * the list and check if the number is greater than 1 + the previous number. If so - * we use the previous number + 1 as the account number. This refills gaps. - * mAccountNumber starts as -1 on a newly created account. It must be -1 for this - * algorithm to work. - * - * I bet there is a much smarter way to do this. Anyone like to suggest it? - */ - Account[] accounts = preferences.getAccounts(); - int[] accountNumbers = new int[accounts.length]; - for (int i = 0; i < accounts.length; i++) { - accountNumbers[i] = accounts[i].getAccountNumber(); - } - Arrays.sort(accountNumbers); - for (int accountNumber : accountNumbers) { - if (accountNumber > mAccountNumber + 1) { - break; - } - mAccountNumber = accountNumber; - } - mAccountNumber++; - - String accountUuids = preferences.mSharedPreferences.getString("accountUuids", ""); - accountUuids += (accountUuids.length() != 0 ? "," : "") + mUuid; - SharedPreferences.Editor editor = preferences.mSharedPreferences.edit(); - editor.putString("accountUuids", accountUuids); - editor.commit(); - } - - SharedPreferences.Editor editor = preferences.mSharedPreferences.edit(); - - editor.putString(mUuid + ".storeUri", Utility.base64Encode(mStoreUri)); - editor.putString(mUuid + ".localStoreUri", mLocalStoreUri); - editor.putString(mUuid + ".transportUri", Utility.base64Encode(mTransportUri)); - editor.putString(mUuid + ".description", mDescription); - editor.putString(mUuid + ".name", mName); - editor.putString(mUuid + ".email", mEmail); - editor.putString(mUuid + ".signature", mSignature); - editor.putString(mUuid + ".alwaysBcc", mAlwaysBcc); - editor.putInt(mUuid + ".automaticCheckIntervalMinutes", mAutomaticCheckIntervalMinutes); - editor.putLong(mUuid + ".lastAutomaticCheckTime", mLastAutomaticCheckTime); - editor.putBoolean(mUuid + ".notifyNewMail", mNotifyNewMail); - editor.putInt(mUuid + ".deletePolicy", mDeletePolicy); - editor.putString(mUuid + ".draftsFolderName", mDraftsFolderName); - editor.putString(mUuid + ".sentFolderName", mSentFolderName); - editor.putString(mUuid + ".trashFolderName", mTrashFolderName); - editor.putString(mUuid + ".outboxFolderName", mOutboxFolderName); - editor.putInt(mUuid + ".accountNumber", mAccountNumber); - editor.putBoolean(mUuid + ".vibrate", mVibrate); - editor.putString(mUuid + ".ringtone", mRingtoneUri); - editor.commit(); - } - - public String toString() { - return mDescription; - } - - public Uri getContentUri() { - return Uri.parse("content://accounts/" + getUuid()); - } - - public String getLocalStoreUri() { - return mLocalStoreUri; - } - - public void setLocalStoreUri(String localStoreUri) { - this.mLocalStoreUri = localStoreUri; - } - - /** - * Returns -1 for never. - */ - public int getAutomaticCheckIntervalMinutes() { - return mAutomaticCheckIntervalMinutes; - } - - /** - * @param automaticCheckIntervalMinutes or -1 for never. - */ - public void setAutomaticCheckIntervalMinutes(int automaticCheckIntervalMinutes) { - this.mAutomaticCheckIntervalMinutes = automaticCheckIntervalMinutes; - } - - public long getLastAutomaticCheckTime() { - return mLastAutomaticCheckTime; - } - - public void setLastAutomaticCheckTime(long lastAutomaticCheckTime) { - this.mLastAutomaticCheckTime = lastAutomaticCheckTime; - } - - public boolean isNotifyNewMail() { - return mNotifyNewMail; - } - - public void setNotifyNewMail(boolean notifyNewMail) { - this.mNotifyNewMail = notifyNewMail; - } - - public int getDeletePolicy() { - return mDeletePolicy; - } - - public void setDeletePolicy(int deletePolicy) { - this.mDeletePolicy = deletePolicy; - } - - public String getDraftsFolderName() { - return mDraftsFolderName; - } - - public void setDraftsFolderName(String draftsFolderName) { - mDraftsFolderName = draftsFolderName; - } - - public String getSentFolderName() { - return mSentFolderName; - } - - public void setSentFolderName(String sentFolderName) { - mSentFolderName = sentFolderName; - } - - public String getTrashFolderName() { - return mTrashFolderName; - } - - public void setTrashFolderName(String trashFolderName) { - mTrashFolderName = trashFolderName; - } - - public String getOutboxFolderName() { - return mOutboxFolderName; - } - - public void setOutboxFolderName(String outboxFolderName) { - mOutboxFolderName = outboxFolderName; - } - - public int getAccountNumber() { - return mAccountNumber; - } - - @Override - public boolean equals(Object o) { - if (o instanceof Account) { - return ((Account)o).mUuid.equals(mUuid); - } - return super.equals(o); - } -} diff --git a/src/com/fsck/k9/EmailAddressAdapter.java b/src/com/fsck/k9/EmailAddressAdapter.java deleted file mode 100644 index f547bafe7..000000000 --- a/src/com/fsck/k9/EmailAddressAdapter.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.fsck.k9; - -import static android.provider.Contacts.ContactMethods.CONTENT_EMAIL_URI; -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.provider.Contacts.ContactMethods; -import android.provider.Contacts.People; -import android.view.View; -import android.widget.ResourceCursorAdapter; -import android.widget.TextView; - -import com.fsck.k9.mail.Address; - -public class EmailAddressAdapter extends ResourceCursorAdapter { - public static final int NAME_INDEX = 1; - - public static final int DATA_INDEX = 2; - - private static final String SORT_ORDER = People.TIMES_CONTACTED + " DESC, " + People.NAME; - - private ContentResolver mContentResolver; - - private static final String[] PROJECTION = { - ContactMethods._ID, // 0 - ContactMethods.NAME, // 1 - ContactMethods.DATA - // 2 - }; - - public EmailAddressAdapter(Context context) { - super(context, R.layout.recipient_dropdown_item, null); - mContentResolver = context.getContentResolver(); - } - - @Override - public final String convertToString(Cursor cursor) { - String name = cursor.getString(NAME_INDEX); - String address = cursor.getString(DATA_INDEX); - - return new Address(address, name).toString(); - } - - @Override - public final void bindView(View view, Context context, Cursor cursor) { - TextView text1 = (TextView)view.findViewById(R.id.text1); - TextView text2 = (TextView)view.findViewById(R.id.text2); - text1.setText(cursor.getString(NAME_INDEX)); - text2.setText(cursor.getString(DATA_INDEX)); - } - - @Override - public Cursor runQueryOnBackgroundThread(CharSequence constraint) { - String where = null; - - if (constraint != null) { - String filter = DatabaseUtils.sqlEscapeString(constraint.toString() + '%'); - - StringBuilder s = new StringBuilder(); - s.append("(people.name LIKE "); - s.append(filter); - s.append(") OR (contact_methods.data LIKE "); - s.append(filter); - s.append(")"); - - where = s.toString(); - } - - return mContentResolver.query(CONTENT_EMAIL_URI, PROJECTION, where, null, SORT_ORDER); - } -} diff --git a/src/com/fsck/k9/EmailAddressValidator.java b/src/com/fsck/k9/EmailAddressValidator.java deleted file mode 100644 index 9a7ca21c3..000000000 --- a/src/com/fsck/k9/EmailAddressValidator.java +++ /dev/null @@ -1,18 +0,0 @@ - -package com.fsck.k9; - -import com.fsck.k9.mail.Address; - -import android.util.Config; -import android.util.Log; -import android.widget.AutoCompleteTextView.Validator; - -public class EmailAddressValidator implements Validator { - public CharSequence fixText(CharSequence invalidText) { - return ""; - } - - public boolean isValid(CharSequence text) { - return Address.parse(text.toString()).length > 0; - } -} diff --git a/src/com/fsck/k9/FixedLengthInputStream.java b/src/com/fsck/k9/FixedLengthInputStream.java deleted file mode 100644 index 457e7c3ca..000000000 --- a/src/com/fsck/k9/FixedLengthInputStream.java +++ /dev/null @@ -1,60 +0,0 @@ - -package com.fsck.k9; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A filtering InputStream that stops allowing reads after the given length has been read. This - * is used to allow a client to read directly from an underlying protocol stream without reading - * past where the protocol handler intended the client to read. - */ -public class FixedLengthInputStream extends InputStream { - private InputStream mIn; - private int mLength; - private int mCount; - - public FixedLengthInputStream(InputStream in, int length) { - this.mIn = in; - this.mLength = length; - } - - @Override - public int available() throws IOException { - return mLength - mCount; - } - - @Override - public int read() throws IOException { - if (mCount < mLength) { - mCount++; - return mIn.read(); - } else { - return -1; - } - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (mCount < mLength) { - int d = mIn.read(b, offset, Math.min(mLength - mCount, length)); - if (d == -1) { - return -1; - } else { - mCount += d; - return d; - } - } else { - return -1; - } - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - public String toString() { - return String.format("FixedLengthInputStream(in=%s, length=%d)", mIn.toString(), mLength); - } -} diff --git a/src/com/fsck/k9/Manifest.java b/src/com/fsck/k9/Manifest.java deleted file mode 100644 index 80158aa5a..000000000 --- a/src/com/fsck/k9/Manifest.java +++ /dev/null @@ -1,14 +0,0 @@ -/* AUTO-GENERATED FILE. DO NOT MODIFY. - * - * This class was automatically generated by the - * aapt tool from the resource data it found. It - * should not be modified by hand. - */ - -package com.fsck.k9; - -public final class Manifest { - public static final class permission { - public static final String READ_ATTACHMENT="com.fsck.k9.permission.READ_ATTACHMENT"; - } -} diff --git a/src/com/fsck/k9/MessagingController.java b/src/com/fsck/k9/MessagingController.java deleted file mode 100644 index 0c98225ce..000000000 --- a/src/com/fsck/k9/MessagingController.java +++ /dev/null @@ -1,1476 +0,0 @@ - -package com.fsck.k9; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -import android.app.Application; -import android.content.Context; -import android.os.Process; -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.mail.FetchProfile; -import com.fsck.k9.mail.Flag; -import com.fsck.k9.mail.Folder; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessageRetrievalListener; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Part; -import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.Transport; -import com.fsck.k9.mail.Folder.FolderType; -import com.fsck.k9.mail.Folder.OpenMode; -import com.fsck.k9.mail.internet.MimeHeader; -import com.fsck.k9.mail.internet.MimeUtility; -import com.fsck.k9.mail.store.LocalStore; -import com.fsck.k9.mail.store.LocalStore.LocalFolder; -import com.fsck.k9.mail.store.LocalStore.LocalMessage; -import com.fsck.k9.mail.store.LocalStore.PendingCommand; - -/** - * Starts a long running (application) Thread that will run through commands - * that require remote mailbox access. This class is used to serialize and - * prioritize these commands. Each method that will submit a command requires a - * MessagingListener instance to be provided. It is expected that that listener - * has also been added as a registered listener using addListener(). When a - * command is to be executed, if the listener that was provided with the command - * is no longer registered the command is skipped. The design idea for the above - * is that when an Activity starts it registers as a listener. When it is paused - * it removes itself. Thus, any commands that that activity submitted are - * removed from the queue once the activity is no longer active. - */ -public class MessagingController implements Runnable { - /** - * The maximum message size that we'll consider to be "small". A small message is downloaded - * in full immediately instead of in pieces. Anything over this size will be downloaded in - * pieces with attachments being left off completely and downloaded on demand. - * - * - * 25k for a "small" message was picked by educated trial and error. - * http://answers.google.com/answers/threadview?id=312463 claims that the - * average size of an email is 59k, which I feel is too large for our - * blind download. The following tests were performed on a download of - * 25 random messages. - *
-     * 5k - 61 seconds,
-     * 25k - 51 seconds,
-     * 55k - 53 seconds,
-     * 
- * So 25k gives good performance and a reasonable data footprint. Sounds good to me. - */ - private static final int MAX_SMALL_MESSAGE_SIZE = (25 * 1024); - - private static final String PENDING_COMMAND_TRASH = - "com.fsck.k9.MessagingController.trash"; - private static final String PENDING_COMMAND_MARK_READ = - "com.fsck.k9.MessagingController.markRead"; - private static final String PENDING_COMMAND_APPEND = - "com.fsck.k9.MessagingController.append"; - - private static MessagingController inst = null; - private BlockingQueue mCommands = new LinkedBlockingQueue(); - private Thread mThread; - private HashSet mListeners = new HashSet(); - private boolean mBusy; - private Application mApplication; - - private MessagingController(Application application) { - mApplication = application; - mThread = new Thread(this); - mThread.start(); - } - - /** - * Gets or creates the singleton instance of MessagingController. Application is used to - * provide a Context to classes that need it. - * @param application - * @return - */ - public synchronized static MessagingController getInstance(Application application) { - if (inst == null) { - inst = new MessagingController(application); - } - return inst; - } - - public boolean isBusy() { - return mBusy; - } - - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - while (true) { - try { - Command command = mCommands.take(); - if (command.listener == null || mListeners.contains(command.listener)) { - mBusy = true; - command.runnable.run(); - for (MessagingListener l : mListeners) { - l.controllerCommandCompleted(mCommands.size() > 0); - } - } - } - catch (Exception e) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "Error running command", e); - } - } - mBusy = false; - } - } - - private void put(String description, MessagingListener listener, Runnable runnable) { - try { - Command command = new Command(); - command.listener = listener; - command.runnable = runnable; - command.description = description; - mCommands.put(command); - } - catch (InterruptedException ie) { - throw new Error(ie); - } - } - - public void addListener(MessagingListener listener) { - mListeners.add(listener); - } - - public void removeListener(MessagingListener listener) { - mListeners.remove(listener); - } - - /** - * Lists folders that are available locally and remotely. This method calls - * listFoldersCallback for local folders before it returns, and then for - * remote folders at some later point. If there are no local folders - * includeRemote is forced by this method. This method should be called from - * a Thread as it may take several seconds to list the local folders. TODO - * this needs to cache the remote folder list - * - * @param account - * @param includeRemote - * @param listener - * @throws MessagingException - */ - public void listFolders( - final Account account, - boolean refreshRemote, - MessagingListener listener) { - for (MessagingListener l : mListeners) { - l.listFoldersStarted(account); - } - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - Folder[] localFolders = localStore.getPersonalNamespaces(); - - if (localFolders == null || localFolders.length == 0) { - refreshRemote = true; - } else { - for (MessagingListener l : mListeners) { - l.listFolders(account, localFolders); - } - } - } - catch (Exception e) { - for (MessagingListener l : mListeners) { - l.listFoldersFailed(account, e.getMessage()); - return; - } - } - if (refreshRemote) { - put("listFolders", listener, new Runnable() { - public void run() { - try { - Store store = Store.getInstance(account.getStoreUri(), mApplication); - - Folder[] remoteFolders = store.getPersonalNamespaces(); - - Store localStore = Store.getInstance( - account.getLocalStoreUri(), - mApplication); - HashSet remoteFolderNames = new HashSet(); - for (int i = 0, count = remoteFolders.length; i < count; i++) { - Folder localFolder = localStore.getFolder(remoteFolders[i].getName()); - if (!localFolder.exists()) { - localFolder.create(FolderType.HOLDS_MESSAGES); - } - remoteFolderNames.add(remoteFolders[i].getName()); - } - - Folder[] localFolders = localStore.getPersonalNamespaces(); - - /* - * Clear out any folders that are no longer on the remote store. - */ - for (Folder localFolder : localFolders) { - String localFolderName = localFolder.getName(); - if (localFolderName.equalsIgnoreCase(k9.INBOX) || - localFolderName.equals(account.getTrashFolderName()) || - localFolderName.equals(account.getOutboxFolderName()) || - localFolderName.equals(account.getDraftsFolderName()) || - localFolderName.equals(account.getSentFolderName())) { - continue; - } - if (!remoteFolderNames.contains(localFolder.getName())) { - localFolder.delete(false); - } - } - - localFolders = localStore.getPersonalNamespaces(); - - for (MessagingListener l : mListeners) { - l.listFolders(account, localFolders); - } - for (MessagingListener l : mListeners) { - l.listFoldersFinished(account); - } - } - catch (Exception e) { - for (MessagingListener l : mListeners) { - l.listFoldersFailed(account, ""); - } - } - } - }); - } else { - for (MessagingListener l : mListeners) { - l.listFoldersFinished(account); - } - } - } - - /** - * List the local message store for the given folder. This work is done - * synchronously. - * - * @param account - * @param folder - * @param listener - * @throws MessagingException - */ - public void listLocalMessages(final Account account, final String folder, - MessagingListener listener) { - for (MessagingListener l : mListeners) { - l.listLocalMessagesStarted(account, folder); - } - - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - Folder localFolder = localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); - Message[] localMessages = localFolder.getMessages(null); - ArrayList messages = new ArrayList(); - for (Message message : localMessages) { - if (!message.isSet(Flag.DELETED)) { - messages.add(message); - } - } - for (MessagingListener l : mListeners) { - l.listLocalMessages(account, folder, messages.toArray(new Message[0])); - } - for (MessagingListener l : mListeners) { - l.listLocalMessagesFinished(account, folder); - } - } - catch (Exception e) { - for (MessagingListener l : mListeners) { - l.listLocalMessagesFailed(account, folder, e.getMessage()); - } - } - } - - public void loadMoreMessages(Account account, String folder, MessagingListener listener) { - try { - LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); - LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - localFolder.setVisibleLimit(localFolder.getVisibleLimit() - + k9.VISIBLE_LIMIT_INCREMENT); - synchronizeMailbox(account, folder, listener); - } - catch (MessagingException me) { - throw new RuntimeException("Unable to set visible limit on folder", me); - } - } - - public void resetVisibleLimits(Account[] accounts) { - for (Account account : accounts) { - try { - LocalStore localStore = - (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication); - localStore.resetVisibleLimits(); - } - catch (MessagingException e) { - Log.e(k9.LOG_TAG, "Unable to reset visible limits", e); - } - } - } - - /** - * Start background synchronization of the specified folder. - * @param account - * @param folder - * @param numNewestMessagesToKeep Specifies the number of messages that should be - * considered as part of the window of available messages. This number effectively limits - * the user's view into the mailbox to the newest (numNewestMessagesToKeep) messages. - * @param listener - */ - public void synchronizeMailbox(final Account account, final String folder, - MessagingListener listener) { - /* - * We don't ever sync the Outbox. - */ - if (folder.equals(account.getOutboxFolderName())) { - return; - } - for (MessagingListener l : mListeners) { - l.synchronizeMailboxStarted(account, folder); - } - put("synchronizeMailbox", listener, new Runnable() { - public void run() { - synchronizeMailboxSynchronous(account, folder); - } - }); - } - - /** - * Start foreground synchronization of the specified folder. This is generally only called - * by synchronizeMailbox. - * @param account - * @param folder - * @param numNewestMessagesToKeep Specifies the number of messages that should be - * considered as part of the window of available messages. This number effectively limits - * the user's view into the mailbox to the newest (numNewestMessagesToKeep) messages. - * @param listener - * - * TODO Break this method up into smaller chunks. - */ - public void synchronizeMailboxSynchronous(final Account account, final String folder) { - for (MessagingListener l : mListeners) { - l.synchronizeMailboxStarted(account, folder); - } - try { - processPendingCommandsSynchronous(account); - - /* - * Get the message list from the local store and create an index of - * the uids within the list. - */ - final LocalStore localStore = - (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication); - final LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); - Message[] localMessages = localFolder.getMessages(null); - HashMap localUidMap = new HashMap(); - for (Message message : localMessages) { - localUidMap.put(message.getUid(), message); - } - - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); - Folder remoteFolder = remoteStore.getFolder(folder); - - /* - * If the folder is a "special" folder we need to see if it exists - * on the remote server. It if does not exist we'll try to create it. If we - * can't create we'll abort. This will happen on every single Pop3 folder as - * designed and on Imap folders during error conditions. This allows us - * to treat Pop3 and Imap the same in this code. - */ - if (folder.equals(account.getTrashFolderName()) || - folder.equals(account.getSentFolderName()) || - folder.equals(account.getDraftsFolderName())) { - if (!remoteFolder.exists()) { - if (!remoteFolder.create(FolderType.HOLDS_MESSAGES)) { - for (MessagingListener l : mListeners) { - l.synchronizeMailboxFinished(account, folder, 0, 0); - } - return; - } - } - } - - /* - * Synchronization process: - Open the folder - Upload any local messages that are marked as PENDING_UPLOAD (Drafts, Sent, Trash) - Get the message count - Get the list of the newest k9.DEFAULT_VISIBLE_LIMIT messages - getMessages(messageCount - k9.DEFAULT_VISIBLE_LIMIT, messageCount) - See if we have each message locally, if not fetch it's flags and envelope - Get and update the unread count for the folder - Update the remote flags of any messages we have locally with an internal date - newer than the remote message. - Get the current flags for any messages we have locally but did not just download - Update local flags - For any message we have locally but not remotely, delete the local message to keep - cache clean. - Download larger parts of any new messages. - (Optional) Download small attachments in the background. - */ - - /* - * Open the remote folder. This pre-loads certain metadata like message count. - */ - remoteFolder.open(OpenMode.READ_WRITE); - - - /* - * Get the remote message count. - */ - int remoteMessageCount = remoteFolder.getMessageCount(); - - int visibleLimit = localFolder.getVisibleLimit(); - - Message[] remoteMessages = new Message[0]; - final ArrayList unsyncedMessages = new ArrayList(); - HashMap remoteUidMap = new HashMap(); - - if (remoteMessageCount > 0) { - /* - * Message numbers start at 1. - */ - int remoteStart = Math.max(0, remoteMessageCount - visibleLimit) + 1; - int remoteEnd = remoteMessageCount; - remoteMessages = remoteFolder.getMessages(remoteStart, remoteEnd, null); - for (Message message : remoteMessages) { - remoteUidMap.put(message.getUid(), message); - } - - - - - - - - /* - * Get a list of the messages that are in the remote list but not on the - * local store, or messages that are in the local store but failed to download - * on the last sync. These are the new messages that we will download. - */ - for (Message message : remoteMessages) { - Message localMessage = localUidMap.get(message.getUid()); - if (localMessage == null || - (!localMessage.isSet(Flag.DELETED) && - !localMessage.isSet(Flag.X_DOWNLOADED_FULL) && - !localMessage.isSet(Flag.X_DOWNLOADED_PARTIAL))) { - unsyncedMessages.add(message); - } - } - } - - - /* - * Trash any remote messages that are marked as trashed locally. - */ - for (Message message : localMessages) { - Message remoteMessage = remoteUidMap.get(message.getUid()); - // skip things deleted on the server side - if (remoteMessage != null && message.isSet(Flag.DELETED)) { - remoteMessage.setFlag(Flag.DELETED, true); - } - - } - - - /* - * A list of messages that were downloaded and which did not have the Seen flag set. - * This will serve to indicate the true "new" message count that will be reported to - * the user via notification. - */ - final ArrayList newMessages = new ArrayList(); - - /* - * Fetch the flags and envelope only of the new messages. This is intended to get us -s * critical data as fast as possible, and then we'll fill in the details. - */ - if (unsyncedMessages.size() > 0) { - - /* - * Reverse the order of the messages. Depending on the server this may get us - * fetch results for newest to oldest. If not, no harm done. - */ - Collections.reverse(unsyncedMessages); - - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.FLAGS); - fp.add(FetchProfile.Item.ENVELOPE); - remoteFolder.fetch(unsyncedMessages.toArray(new Message[0]), fp, - new MessageRetrievalListener() { - public void messageFinished(Message message, int number, int ofTotal) { - try { - // Store the new message locally - localFolder.appendMessages(new Message[] { - message - }); - - // And include it in the view - if (message.getSubject() != null && - message.getFrom() != null) { - /* - * We check to make sure that we got something worth - * showing (subject and from) because some protocols - * (POP) may not be able to give us headers for - * ENVELOPE, only size. - */ - for (MessagingListener l : mListeners) { - l.synchronizeMailboxNewMessage(account, folder, - localFolder.getMessage(message.getUid())); - } - } - - if (!message.isSet(Flag.SEEN)) { - newMessages.add(message); - } - } - catch (Exception e) { - Log.e(k9.LOG_TAG, - "Error while storing downloaded message.", - e); - } - } - - public void messageStarted(String uid, int number, int ofTotal) { - } - }); - } - - /* - * Refresh the flags for any messages in the local store that we didn't just - * download. - */ - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.FLAGS); - remoteFolder.fetch(remoteMessages, fp, null); - for (Message remoteMessage : remoteMessages) { - Message localMessage = localFolder.getMessage(remoteMessage.getUid()); - if (localMessage == null) { - continue; - } - if (remoteMessage.isSet(Flag.SEEN) != localMessage.isSet(Flag.SEEN)) { - localMessage.setFlag(Flag.SEEN, remoteMessage.isSet(Flag.SEEN)); - for (MessagingListener l : mListeners) { - l.synchronizeMailboxNewMessage(account, folder, localMessage); - } - } - } - - /* - * Get and store the unread message count. - */ - int remoteUnreadMessageCount = remoteFolder.getUnreadMessageCount(); - if (remoteUnreadMessageCount == -1) { - localFolder.setUnreadMessageCount(localFolder.getUnreadMessageCount() - + newMessages.size()); - } - else { - localFolder.setUnreadMessageCount(remoteUnreadMessageCount); - } - - /* - * Remove any messages that are in the local store but no longer on the remote store. - */ - for (Message localMessage : localMessages) { - if (remoteUidMap.get(localMessage.getUid()) == null) { - localMessage.setFlag(Flag.X_DESTROYED, true); - for (MessagingListener l : mListeners) { - l.synchronizeMailboxRemovedMessage(account, folder, localMessage); - } - } - } - - /* - * Now we download the actual content of messages. - */ - ArrayList largeMessages = new ArrayList(); - ArrayList smallMessages = new ArrayList(); - for (Message message : unsyncedMessages) { - /* - * Sort the messages into two buckets, small and large. Small messages will be - * downloaded fully and large messages will be downloaded in parts. By sorting - * into two buckets we can pipeline the commands for each set of messages - * into a single command to the server saving lots of round trips. - */ - if (message.getSize() > (MAX_SMALL_MESSAGE_SIZE)) { - largeMessages.add(message); - } else { - smallMessages.add(message); - } - } - /* - * Grab the content of the small messages first. This is going to - * be very fast and at very worst will be a single up of a few bytes and a single - * download of 625k. - */ - fp = new FetchProfile(); - fp.add(FetchProfile.Item.BODY); - remoteFolder.fetch(smallMessages.toArray(new Message[smallMessages.size()]), - fp, new MessageRetrievalListener() { - public void messageFinished(Message message, int number, int ofTotal) { - try { - // Store the updated message locally - localFolder.appendMessages(new Message[] { - message - }); - - Message localMessage = localFolder.getMessage(message.getUid()); - - // Set a flag indicating this message has now be fully downloaded - localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); - - // Update the listener with what we've found - for (MessagingListener l : mListeners) { - l.synchronizeMailboxNewMessage( - account, - folder, - localMessage); - } - } - catch (MessagingException me) { - - } - } - - public void messageStarted(String uid, int number, int ofTotal) { - } - }); - - /* - * Now do the large messages that require more round trips. - */ - fp.clear(); - fp.add(FetchProfile.Item.STRUCTURE); - remoteFolder.fetch(largeMessages.toArray(new Message[largeMessages.size()]), - fp, null); - for (Message message : largeMessages) { - if (message.getBody() == null) { - /* - * The provider was unable to get the structure of the message, so - * we'll download a reasonable portion of the messge and mark it as - * incomplete so the entire thing can be downloaded later if the user - * wishes to download it. - */ - fp.clear(); - fp.add(FetchProfile.Item.BODY_SANE); - /* - * TODO a good optimization here would be to make sure that all Stores set - * the proper size after this fetch and compare the before and after size. If - * they equal we can mark this SYNCHRONIZED instead of PARTIALLY_SYNCHRONIZED - */ - - remoteFolder.fetch(new Message[] { message }, fp, null); - // Store the updated message locally - localFolder.appendMessages(new Message[] { - message - }); - - Message localMessage = localFolder.getMessage(message.getUid()); - - // Set a flag indicating that the message has been partially downloaded and - // is ready for view. - localMessage.setFlag(Flag.X_DOWNLOADED_PARTIAL, true); - } else { - /* - * We have a structure to deal with, from which - * we can pull down the parts we want to actually store. - * Build a list of parts we are interested in. Text parts will be downloaded - * right now, attachments will be left for later. - */ - - ArrayList viewables = new ArrayList(); - ArrayList attachments = new ArrayList(); - MimeUtility.collectParts(message, viewables, attachments); - - /* - * Now download the parts we're interested in storing. - */ - for (Part part : viewables) { - fp.clear(); - fp.add(part); - // TODO what happens if the network connection dies? We've got partial - // messages with incorrect status stored. - remoteFolder.fetch(new Message[] { message }, fp, null); - } - // Store the updated message locally - localFolder.appendMessages(new Message[] { - message - }); - - Message localMessage = localFolder.getMessage(message.getUid()); - - // Set a flag indicating this message has been fully downloaded and can be - // viewed. - localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); - } - - // Update the listener with what we've found - for (MessagingListener l : mListeners) { - l.synchronizeMailboxNewMessage( - account, - folder, - localFolder.getMessage(message.getUid())); - } - } - - - /* - * Notify listeners that we're finally done. - */ - for (MessagingListener l : mListeners) { - l.synchronizeMailboxFinished( - account, - folder, - remoteFolder.getMessageCount(), newMessages.size()); - } - - remoteFolder.close(false); - localFolder.close(false); - } - catch (Exception e) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "synchronizeMailbox", e); - } - for (MessagingListener l : mListeners) { - l.synchronizeMailboxFailed( - account, - folder, - e.getMessage()); - } - } - } - - private void queuePendingCommand(Account account, PendingCommand command) { - try { - LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); - localStore.addPendingCommand(command); - } - catch (Exception e) { - throw new RuntimeException("Unable to enqueue pending command", e); - } - } - - private void processPendingCommands(final Account account) { - put("processPendingCommands", null, new Runnable() { - public void run() { - try { - processPendingCommandsSynchronous(account); - } - catch (MessagingException me) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "processPendingCommands", me); - } - /* - * Ignore any exceptions from the commands. Commands will be processed - * on the next round. - */ - } - } - }); - } - - private void processPendingCommandsSynchronous(Account account) throws MessagingException { - LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); - ArrayList commands = localStore.getPendingCommands(); - for (PendingCommand command : commands) { - /* - * We specifically do not catch any exceptions here. If a command fails it is - * most likely due to a server or IO error and it must be retried before any - * other command processes. This maintains the order of the commands. - */ - if (PENDING_COMMAND_APPEND.equals(command.command)) { - processPendingAppend(command, account); - } - else if (PENDING_COMMAND_MARK_READ.equals(command.command)) { - processPendingMarkRead(command, account); - } - else if (PENDING_COMMAND_TRASH.equals(command.command)) { - processPendingTrash(command, account); - } - localStore.removePendingCommand(command); - } - } - - /** - * Process a pending append message command. This command uploads a local message to the - * server, first checking to be sure that the server message is not newer than - * the local message. Once the local message is successfully processed it is deleted so - * that the server message will be synchronized down without an additional copy being - * created. - * TODO update the local message UID instead of deleteing it - * - * @param command arguments = (String folder, String uid) - * @param account - * @throws MessagingException - */ - private void processPendingAppend(PendingCommand command, Account account) - throws MessagingException { - String folder = command.arguments[0]; - String uid = command.arguments[1]; - - LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); - LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - LocalMessage localMessage = (LocalMessage) localFolder.getMessage(uid); - - if (localMessage == null) { - return; - } - - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); - Folder remoteFolder = remoteStore.getFolder(folder); - if (!remoteFolder.exists()) { - if (!remoteFolder.create(FolderType.HOLDS_MESSAGES)) { - return; - } - } - remoteFolder.open(OpenMode.READ_WRITE); - if (remoteFolder.getMode() != OpenMode.READ_WRITE) { - return; - } - - Message remoteMessage = null; - if (!localMessage.getUid().startsWith("Local") - && !localMessage.getUid().contains("-")) { - remoteMessage = remoteFolder.getMessage(localMessage.getUid()); - } - - if (remoteMessage == null) { - /* - * If the message does not exist remotely we just upload it and then - * update our local copy with the new uid. - */ - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.BODY); - localFolder.fetch(new Message[] { localMessage }, fp, null); - String oldUid = localMessage.getUid(); - remoteFolder.appendMessages(new Message[] { localMessage }); - localFolder.changeUid(localMessage); - for (MessagingListener l : mListeners) { - l.messageUidChanged(account, folder, oldUid, localMessage.getUid()); - } - } - else { - /* - * If the remote message exists we need to determine which copy to keep. - */ - /* - * See if the remote message is newer than ours. - */ - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.ENVELOPE); - remoteFolder.fetch(new Message[] { remoteMessage }, fp, null); - Date localDate = localMessage.getInternalDate(); - Date remoteDate = remoteMessage.getInternalDate(); - if (remoteDate.compareTo(localDate) > 0) { - /* - * If the remote message is newer than ours we'll just - * delete ours and move on. A sync will get the server message - * if we need to be able to see it. - */ - localMessage.setFlag(Flag.DELETED, true); - } - else { - /* - * Otherwise we'll upload our message and then delete the remote message. - */ - fp.clear(); - fp = new FetchProfile(); - fp.add(FetchProfile.Item.BODY); - localFolder.fetch(new Message[] { localMessage }, fp, null); - String oldUid = localMessage.getUid(); - remoteFolder.appendMessages(new Message[] { localMessage }); - localFolder.changeUid(localMessage); - for (MessagingListener l : mListeners) { - l.messageUidChanged(account, folder, oldUid, localMessage.getUid()); - } - remoteMessage.setFlag(Flag.DELETED, true); - } - } - } - - /** - * Process a pending trash message command. - * - * @param command arguments = (String folder, String uid) - * @param account - * @throws MessagingException - */ - private void processPendingTrash(PendingCommand command, Account account) - throws MessagingException { - String folder = command.arguments[0]; - String uid = command.arguments[1]; - - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); - Folder remoteFolder = remoteStore.getFolder(folder); - if (!remoteFolder.exists()) { - return; - } - remoteFolder.open(OpenMode.READ_WRITE); - if (remoteFolder.getMode() != OpenMode.READ_WRITE) { - return; - } - - Message remoteMessage = null; - if (!uid.startsWith("Local") - && !uid.contains("-")) { - remoteMessage = remoteFolder.getMessage(uid); - } - if (remoteMessage == null) { - return; - } - - Folder remoteTrashFolder = remoteStore.getFolder(account.getTrashFolderName()); - /* - * Attempt to copy the remote message to the remote trash folder. - */ - if (!remoteTrashFolder.exists()) { - /* - * If the remote trash folder doesn't exist we try to create it. - */ - remoteTrashFolder.create(FolderType.HOLDS_MESSAGES); - } - - if (remoteTrashFolder.exists()) { - remoteFolder.copyMessages(new Message[] { remoteMessage }, remoteTrashFolder); - } - - remoteMessage.setFlag(Flag.DELETED, true); - remoteFolder.expunge(); - } - - /** - * Processes a pending mark read or unread command. - * - * @param command arguments = (String folder, String uid, boolean read) - * @param account - */ - private void processPendingMarkRead(PendingCommand command, Account account) - throws MessagingException { - String folder = command.arguments[0]; - String uid = command.arguments[1]; - boolean read = Boolean.parseBoolean(command.arguments[2]); - - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); - Folder remoteFolder = remoteStore.getFolder(folder); - if (!remoteFolder.exists()) { - return; - } - remoteFolder.open(OpenMode.READ_WRITE); - if (remoteFolder.getMode() != OpenMode.READ_WRITE) { - return; - } - Message remoteMessage = null; - if (!uid.startsWith("Local") - && !uid.contains("-")) { - remoteMessage = remoteFolder.getMessage(uid); - } - if (remoteMessage == null) { - return; - } - remoteMessage.setFlag(Flag.SEEN, read); - } - - /** - * Mark the message with the given account, folder and uid either Seen or not Seen. - * @param account - * @param folder - * @param uid - * @param seen - */ - public void markMessageRead( - final Account account, - final String folder, - final String uid, - final boolean seen) { - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - Folder localFolder = localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); - - Message message = localFolder.getMessage(uid); - message.setFlag(Flag.SEEN, seen); - PendingCommand command = new PendingCommand(); - command.command = PENDING_COMMAND_MARK_READ; - command.arguments = new String[] { folder, uid, Boolean.toString(seen) }; - queuePendingCommand(account, command); - processPendingCommands(account); - } - catch (MessagingException me) { - throw new RuntimeException(me); - } - } - - private void loadMessageForViewRemote(final Account account, final String folder, - final String uid, MessagingListener listener) { - put("loadMessageForViewRemote", listener, new Runnable() { - public void run() { - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); - - Message message = localFolder.getMessage(uid); - - if (message.isSet(Flag.X_DOWNLOADED_FULL)) { - /* - * If the message has been synchronized since we were called we'll - * just hand it back cause it's ready to go. - */ - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.ENVELOPE); - fp.add(FetchProfile.Item.BODY); - localFolder.fetch(new Message[] { message }, fp, null); - - for (MessagingListener l : mListeners) { - l.loadMessageForViewBodyAvailable(account, folder, uid, message); - } - for (MessagingListener l : mListeners) { - l.loadMessageForViewFinished(account, folder, uid, message); - } - localFolder.close(false); - return; - } - - /* - * At this point the message is not available, so we need to download it - * fully if possible. - */ - - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); - Folder remoteFolder = remoteStore.getFolder(folder); - remoteFolder.open(OpenMode.READ_WRITE); - - // Get the remote message and fully download it - Message remoteMessage = remoteFolder.getMessage(uid); - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.BODY); - remoteFolder.fetch(new Message[] { remoteMessage }, fp, null); - - // Store the message locally and load the stored message into memory - localFolder.appendMessages(new Message[] { remoteMessage }); - message = localFolder.getMessage(uid); - localFolder.fetch(new Message[] { message }, fp, null); - - // This is a view message request, so mark it read - if (!message.isSet(Flag.SEEN)) { - markMessageRead(account, folder, uid, true); - } - - // Mark that this message is now fully synched - message.setFlag(Flag.X_DOWNLOADED_FULL, true); - - for (MessagingListener l : mListeners) { - l.loadMessageForViewBodyAvailable(account, folder, uid, message); - } - for (MessagingListener l : mListeners) { - l.loadMessageForViewFinished(account, folder, uid, message); - } - remoteFolder.close(false); - localFolder.close(false); - } - catch (Exception e) { - for (MessagingListener l : mListeners) { - l.loadMessageForViewFailed(account, folder, uid, e.getMessage()); - } - } - } - }); - } - - public void loadMessageForView(final Account account, final String folder, final String uid, - MessagingListener listener) { - for (MessagingListener l : mListeners) { - l.loadMessageForViewStarted(account, folder, uid); - } - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); - - Message message = localFolder.getMessage(uid); - - for (MessagingListener l : mListeners) { - l.loadMessageForViewHeadersAvailable(account, folder, uid, message); - } - - if (!message.isSet(Flag.X_DOWNLOADED_FULL)) { - loadMessageForViewRemote(account, folder, uid, listener); - localFolder.close(false); - return; - } - - if (!message.isSet(Flag.SEEN)) { - markMessageRead(account, folder, uid, true); - } - - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.ENVELOPE); - fp.add(FetchProfile.Item.BODY); - localFolder.fetch(new Message[] { - message - }, fp, null); - - for (MessagingListener l : mListeners) { - l.loadMessageForViewBodyAvailable(account, folder, uid, message); - } - - for (MessagingListener l : mListeners) { - l.loadMessageForViewFinished(account, folder, uid, message); - } - localFolder.close(false); - } - catch (Exception e) { - for (MessagingListener l : mListeners) { - l.loadMessageForViewFailed(account, folder, uid, e.getMessage()); - } - } - } - - /** - * Attempts to load the attachment specified by part from the given account and message. - * @param account - * @param message - * @param part - * @param listener - */ - public void loadAttachment( - final Account account, - final Message message, - final Part part, - final Object tag, - MessagingListener listener) { - /* - * Check if the attachment has already been downloaded. If it has there's no reason to - * download it, so we just tell the listener that it's ready to go. - */ - try { - if (part.getBody() != null) { - for (MessagingListener l : mListeners) { - l.loadAttachmentStarted(account, message, part, tag, false); - } - - for (MessagingListener l : mListeners) { - l.loadAttachmentFinished(account, message, part, tag); - } - return; - } - } - catch (MessagingException me) { - /* - * If the header isn't there the attachment isn't downloaded yet, so just continue - * on. - */ - } - - for (MessagingListener l : mListeners) { - l.loadAttachmentStarted(account, message, part, tag, true); - } - - put("loadAttachment", listener, new Runnable() { - public void run() { - try { - LocalStore localStore = - (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication); - /* - * We clear out any attachments already cached in the entire store and then - * we update the passed in message to reflect that there are no cached - * attachments. This is in support of limiting the account to having one - * attachment downloaded at a time. - */ - localStore.pruneCachedAttachments(); - ArrayList viewables = new ArrayList(); - ArrayList attachments = new ArrayList(); - MimeUtility.collectParts(message, viewables, attachments); - for (Part attachment : attachments) { - attachment.setBody(null); - } - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); - LocalFolder localFolder = - (LocalFolder) localStore.getFolder(message.getFolder().getName()); - Folder remoteFolder = remoteStore.getFolder(message.getFolder().getName()); - remoteFolder.open(OpenMode.READ_WRITE); - - FetchProfile fp = new FetchProfile(); - fp.add(part); - remoteFolder.fetch(new Message[] { message }, fp, null); - localFolder.updateMessage((LocalMessage)message); - localFolder.close(false); - for (MessagingListener l : mListeners) { - l.loadAttachmentFinished(account, message, part, tag); - } - } - catch (MessagingException me) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "", me); - } - for (MessagingListener l : mListeners) { - l.loadAttachmentFailed(account, message, part, tag, me.getMessage()); - } - } - } - }); - } - - /** - * Stores the given message in the Outbox and starts a sendPendingMessages command to - * attempt to send the message. - * @param account - * @param message - * @param listener - */ - public void sendMessage(final Account account, - final Message message, - MessagingListener listener) { - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - LocalFolder localFolder = - (LocalFolder) localStore.getFolder(account.getOutboxFolderName()); - localFolder.open(OpenMode.READ_WRITE); - localFolder.appendMessages(new Message[] { - message - }); - Message localMessage = localFolder.getMessage(message.getUid()); - localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); - localFolder.close(false); - sendPendingMessages(account, null); - } - catch (Exception e) { - for (MessagingListener l : mListeners) { - // TODO general failed - } - } - } - - /** - * Attempt to send any messages that are sitting in the Outbox. - * @param account - * @param listener - */ - public void sendPendingMessages(final Account account, - MessagingListener listener) { - put("sendPendingMessages", listener, new Runnable() { - public void run() { - sendPendingMessagesSynchronous(account); - } - }); - } - - /** - * Attempt to send any messages that are sitting in the Outbox. - * @param account - * @param listener - */ - public void sendPendingMessagesSynchronous(final Account account) { - try { - Store localStore = Store.getInstance( - account.getLocalStoreUri(), - mApplication); - Folder localFolder = localStore.getFolder( - account.getOutboxFolderName()); - if (!localFolder.exists()) { - return; - } - localFolder.open(OpenMode.READ_WRITE); - - Message[] localMessages = localFolder.getMessages(null); - - /* - * The profile we will use to pull all of the content - * for a given local message into memory for sending. - */ - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.ENVELOPE); - fp.add(FetchProfile.Item.BODY); - - LocalFolder localSentFolder = - (LocalFolder) localStore.getFolder( - account.getSentFolderName()); - - Transport transport = Transport.getInstance(account.getTransportUri()); - for (Message message : localMessages) { - try { - localFolder.fetch(new Message[] { message }, fp, null); - try { - message.setFlag(Flag.X_SEND_IN_PROGRESS, true); - transport.sendMessage(message); - message.setFlag(Flag.X_SEND_IN_PROGRESS, false); - localFolder.copyMessages( - new Message[] { message }, - localSentFolder); - - PendingCommand command = new PendingCommand(); - command.command = PENDING_COMMAND_APPEND; - command.arguments = - new String[] { - localSentFolder.getName(), - message.getUid() }; - queuePendingCommand(account, command); - processPendingCommands(account); - message.setFlag(Flag.X_DESTROYED, true); - } - catch (Exception e) { - message.setFlag(Flag.X_SEND_FAILED, true); - } - } - catch (Exception e) { - /* - * We ignore this exception because a future refresh will retry this - * message. - */ - } - } - localFolder.expunge(); - if (localFolder.getMessageCount() == 0) { - localFolder.delete(false); - } - for (MessagingListener l : mListeners) { - l.sendPendingMessagesCompleted(account); - } - } - catch (Exception e) { - for (MessagingListener l : mListeners) { - // TODO general failed - } - } - } - - /** - * We do the local portion of this synchronously because other activities may have to make - * updates based on what happens here - * @param account - * @param folder - * @param message - * @param listener - */ - public void deleteMessage(final Account account, final String folder, final Message message, - MessagingListener listener) { - if (folder.equals(account.getTrashFolderName())) { - return; - } - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - Folder localFolder = localStore.getFolder(folder); - Folder localTrashFolder = localStore.getFolder(account.getTrashFolderName()); - - localFolder.copyMessages(new Message[] { message }, localTrashFolder); - message.setFlag(Flag.DELETED, true); - - if (account.getDeletePolicy() == Account.DELETE_POLICY_ON_DELETE) { - PendingCommand command = new PendingCommand(); - command.command = PENDING_COMMAND_TRASH; - command.arguments = new String[] { folder, message.getUid() }; - queuePendingCommand(account, command); - processPendingCommands(account); - } - } - catch (MessagingException me) { - throw new RuntimeException("Error deleting message from local store.", me); - } - } - - public void emptyTrash(final Account account, MessagingListener listener) { - put("emptyTrash", listener, new Runnable() { - public void run() { - // TODO IMAP - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - Folder localFolder = localStore.getFolder(account.getTrashFolderName()); - localFolder.open(OpenMode.READ_WRITE); - Message[] messages = localFolder.getMessages(null); - localFolder.setFlags(messages, new Flag[] { - Flag.DELETED - }, true); - localFolder.close(true); - for (MessagingListener l : mListeners) { - l.emptyTrashCompleted(account); - } - } - catch (Exception e) { - // TODO - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "emptyTrash"); - } - } - } - }); - } - - /** - * Checks mail for one or multiple accounts. If account is null all accounts - * are checked. - * - * @param context - * @param account - * @param listener - */ - public void checkMail(final Context context, final Account account, - final MessagingListener listener) { - for (MessagingListener l : mListeners) { - l.checkMailStarted(context, account); - } - put("checkMail", listener, new Runnable() { - public void run() { - Account[] accounts; - if (account != null) { - accounts = new Account[] { - account - }; - } else { - accounts = Preferences.getPreferences(context).getAccounts(); - } - for (Account account : accounts) { - sendPendingMessagesSynchronous(account); - synchronizeMailboxSynchronous(account, k9.INBOX); - } - for (MessagingListener l : mListeners) { - l.checkMailFinished(context, account); - } - } - }); - } - - public void saveDraft(final Account account, final Message message) { - try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); - LocalFolder localFolder = - (LocalFolder) localStore.getFolder(account.getDraftsFolderName()); - localFolder.open(OpenMode.READ_WRITE); - localFolder.appendMessages(new Message[] { - message - }); - Message localMessage = localFolder.getMessage(message.getUid()); - localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); - - PendingCommand command = new PendingCommand(); - command.command = PENDING_COMMAND_APPEND; - command.arguments = new String[] { - localFolder.getName(), - localMessage.getUid() }; - queuePendingCommand(account, command); - processPendingCommands(account); - } - catch (MessagingException e) { - Log.e(k9.LOG_TAG, "Unable to save message as draft.", e); - } - } - - class Command { - public Runnable runnable; - - public MessagingListener listener; - - public String description; - } -} diff --git a/src/com/fsck/k9/MessagingListener.java b/src/com/fsck/k9/MessagingListener.java deleted file mode 100644 index 17780e778..000000000 --- a/src/com/fsck/k9/MessagingListener.java +++ /dev/null @@ -1,132 +0,0 @@ - -package com.fsck.k9; - -import android.content.Context; - -import com.fsck.k9.mail.Folder; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.Part; - -/** - * Defines the interface that MessagingController will use to callback to requesters. This class - * is defined as non-abstract so that someone who wants to receive only a few messages can - * do so without implementing the entire interface. It is highly recommended that users of - * this interface use the @Override annotation in their implementations to avoid being caught by - * changes in this class. - */ -public class MessagingListener { - public void listFoldersStarted(Account account) { - } - - public void listFolders(Account account, Folder[] folders) { - } - - public void listFoldersFailed(Account account, String message) { - } - - public void listFoldersFinished(Account account) { - } - - public void listLocalMessagesStarted(Account account, String folder) { - } - - public void listLocalMessages(Account account, String folder, Message[] messages) { - } - - public void listLocalMessagesFailed(Account account, String folder, String message) { - } - - public void listLocalMessagesFinished(Account account, String folder) { - } - - public void synchronizeMailboxStarted(Account account, String folder) { - } - - public void synchronizeMailboxNewMessage(Account account, String folder, Message message) { - } - - public void synchronizeMailboxRemovedMessage(Account account, String folder,Message message) { - } - - public void synchronizeMailboxFinished(Account account, String folder, - int totalMessagesInMailbox, int numNewMessages) { - } - - public void synchronizeMailboxFailed(Account account, String folder, - String message) { - } - - public void loadMessageForViewStarted(Account account, String folder, String uid) { - } - - public void loadMessageForViewHeadersAvailable(Account account, String folder, String uid, - Message message) { - } - - public void loadMessageForViewBodyAvailable(Account account, String folder, String uid, - Message message) { - } - - public void loadMessageForViewFinished(Account account, String folder, String uid, - Message message) { - } - - public void loadMessageForViewFailed(Account account, String folder, String uid, String message) { - } - - public void checkMailStarted(Context context, Account account) { - } - - public void checkMailFinished(Context context, Account account) { - } - - public void checkMailFailed(Context context, Account account, String reason) { - } - - public void sendPendingMessagesCompleted(Account account) { - } - - public void emptyTrashCompleted(Account account) { - } - - public void messageUidChanged(Account account, String folder, String oldUid, String newUid) { - - } - - public void loadAttachmentStarted( - Account account, - Message message, - Part part, - Object tag, - boolean requiresDownload) - { - } - - public void loadAttachmentFinished( - Account account, - Message message, - Part part, - Object tag) - { - } - - public void loadAttachmentFailed( - Account account, - Message message, - Part part, - Object tag, - String reason) - { - } - - /** - * General notification messages subclasses can override to be notified that the controller - * has completed a command. This is useful for turning off progress indicators that may have - * been left over from previous commands. - * @param moreCommandsToRun True if the controller will continue on to another command - * immediately. - */ - public void controllerCommandCompleted(boolean moreCommandsToRun) { - - } -} diff --git a/src/com/fsck/k9/PeekableInputStream.java b/src/com/fsck/k9/PeekableInputStream.java deleted file mode 100644 index 2039c7ed0..000000000 --- a/src/com/fsck/k9/PeekableInputStream.java +++ /dev/null @@ -1,64 +0,0 @@ - -package com.fsck.k9; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A filtering InputStream that allows single byte "peeks" without consuming the byte. The - * client of this stream can call peek() to see the next available byte in the stream - * and a subsequent read will still return the peeked byte. - */ -public class PeekableInputStream extends InputStream { - private InputStream mIn; - private boolean mPeeked; - private int mPeekedByte; - - public PeekableInputStream(InputStream in) { - this.mIn = in; - } - - @Override - public int read() throws IOException { - if (!mPeeked) { - return mIn.read(); - } else { - mPeeked = false; - return mPeekedByte; - } - } - - public int peek() throws IOException { - if (!mPeeked) { - mPeekedByte = read(); - mPeeked = true; - } - return mPeekedByte; - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (!mPeeked) { - return mIn.read(b, offset, length); - } else { - b[0] = (byte)mPeekedByte; - mPeeked = false; - int r = mIn.read(b, offset + 1, length - 1); - if (r == -1) { - return 1; - } else { - return r + 1; - } - } - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - public String toString() { - return String.format("PeekableInputStream(in=%s, peeked=%b, peekedByte=%d)", - mIn.toString(), mPeeked, mPeekedByte); - } -} diff --git a/src/com/fsck/k9/Preferences.java b/src/com/fsck/k9/Preferences.java deleted file mode 100644 index 75b75364a..000000000 --- a/src/com/fsck/k9/Preferences.java +++ /dev/null @@ -1,123 +0,0 @@ - -package com.fsck.k9; - -import java.util.Arrays; - -import android.content.Context; -import android.content.SharedPreferences; -import android.net.Uri; -import android.util.Config; -import android.util.Log; - -public class Preferences { - private static Preferences preferences; - - SharedPreferences mSharedPreferences; - - private Preferences(Context context) { - mSharedPreferences = context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE); - } - - /** - * TODO need to think about what happens if this gets GCed along with the - * Activity that initialized it. Do we lose ability to read Preferences in - * further Activities? Maybe this should be stored in the Application - * context. - * - * @return - */ - public static synchronized Preferences getPreferences(Context context) { - if (preferences == null) { - preferences = new Preferences(context); - } - return preferences; - } - - /** - * Returns an array of the accounts on the system. If no accounts are - * registered the method returns an empty array. - * - * @return - */ - public Account[] getAccounts() { - String accountUuids = mSharedPreferences.getString("accountUuids", null); - if (accountUuids == null || accountUuids.length() == 0) { - return new Account[] {}; - } - String[] uuids = accountUuids.split(","); - Account[] accounts = new Account[uuids.length]; - for (int i = 0, length = uuids.length; i < length; i++) { - accounts[i] = new Account(this, uuids[i]); - } - return accounts; - } - - public Account getAccountByContentUri(Uri uri) { - return new Account(this, uri.getPath().substring(1)); - } - - /** - * Returns the Account marked as default. If no account is marked as default - * the first account in the list is marked as default and then returned. If - * there are no accounts on the system the method returns null. - * - * @return - */ - public Account getDefaultAccount() { - String defaultAccountUuid = mSharedPreferences.getString("defaultAccountUuid", null); - Account defaultAccount = null; - Account[] accounts = getAccounts(); - if (defaultAccountUuid != null) { - for (Account account : accounts) { - if (account.getUuid().equals(defaultAccountUuid)) { - defaultAccount = account; - break; - } - } - } - - if (defaultAccount == null) { - if (accounts.length > 0) { - defaultAccount = accounts[0]; - setDefaultAccount(defaultAccount); - } - } - - return defaultAccount; - } - - public void setDefaultAccount(Account account) { - mSharedPreferences.edit().putString("defaultAccountUuid", account.getUuid()).commit(); - } - - public void setEnableDebugLogging(boolean value) { - mSharedPreferences.edit().putBoolean("enableDebugLogging", value).commit(); - } - - public boolean geteEnableDebugLogging() { - return mSharedPreferences.getBoolean("enableDebugLogging", false); - } - - public void setEnableSensitiveLogging(boolean value) { - mSharedPreferences.edit().putBoolean("enableSensitiveLogging", value).commit(); - } - - public boolean getEnableSensitiveLogging() { - return mSharedPreferences.getBoolean("enableSensitiveLogging", false); - } - - public void save() { - } - - public void clear() { - mSharedPreferences.edit().clear().commit(); - } - - public void dump() { - if (Config.LOGV) { - for (String key : mSharedPreferences.getAll().keySet()) { - Log.v(k9.LOG_TAG, key + " = " + mSharedPreferences.getAll().get(key)); - } - } - } -} diff --git a/src/com/fsck/k9/R.java b/src/com/fsck/k9/R.java deleted file mode 100644 index 2f543cc9d..000000000 --- a/src/com/fsck/k9/R.java +++ /dev/null @@ -1,452 +0,0 @@ -/* AUTO-GENERATED FILE. DO NOT MODIFY. - * - * This class was automatically generated by the - * aapt tool from the resource data it found. It - * should not be modified by hand. - */ - -package com.fsck.k9; - -public final class R { - public static final class array { - public static final int account_settings_check_frequency_entries=0x7f050000; - public static final int account_settings_check_frequency_values=0x7f050001; - } - public static final class attr { - } - public static final class color { - public static final int folder_message_list_child_background=0x7f070000; - } - public static final class dimen { - public static final int button_minWidth=0x7f080000; - } - public static final class drawable { - public static final int appointment_indicator_leftside_1=0x7f020000; - public static final int appointment_indicator_leftside_10=0x7f020001; - public static final int appointment_indicator_leftside_11=0x7f020002; - public static final int appointment_indicator_leftside_12=0x7f020003; - public static final int appointment_indicator_leftside_13=0x7f020004; - public static final int appointment_indicator_leftside_14=0x7f020005; - public static final int appointment_indicator_leftside_15=0x7f020006; - public static final int appointment_indicator_leftside_16=0x7f020007; - public static final int appointment_indicator_leftside_17=0x7f020008; - public static final int appointment_indicator_leftside_18=0x7f020009; - public static final int appointment_indicator_leftside_19=0x7f02000a; - public static final int appointment_indicator_leftside_2=0x7f02000b; - public static final int appointment_indicator_leftside_20=0x7f02000c; - public static final int appointment_indicator_leftside_21=0x7f02000d; - public static final int appointment_indicator_leftside_3=0x7f02000e; - public static final int appointment_indicator_leftside_4=0x7f02000f; - public static final int appointment_indicator_leftside_5=0x7f020010; - public static final int appointment_indicator_leftside_6=0x7f020011; - public static final int appointment_indicator_leftside_7=0x7f020012; - public static final int appointment_indicator_leftside_8=0x7f020013; - public static final int appointment_indicator_leftside_9=0x7f020014; - public static final int attached_image_placeholder=0x7f020015; - public static final int bottombar_565=0x7f020016; - public static final int btn_dialog=0x7f020017; - public static final int btn_dialog_disable=0x7f020018; - public static final int btn_dialog_disable_focused=0x7f020019; - public static final int btn_dialog_normal=0x7f02001a; - public static final int btn_dialog_pressed=0x7f02001b; - public static final int btn_dialog_selected=0x7f02001c; - public static final int button_indicator_next=0x7f02001d; - public static final int divider_horizontal_email=0x7f02001e; - public static final int email_quoted_bar=0x7f02001f; - public static final int expander_ic_folder=0x7f020020; - public static final int expander_ic_folder_maximized=0x7f020021; - public static final int expander_ic_folder_minimized=0x7f020022; - public static final int folder_message_list_child_background=0x7f020023; - public static final int ic_delete=0x7f020024; - public static final int ic_email_attachment=0x7f020025; - public static final int ic_email_attachment_small=0x7f020026; - public static final int ic_email_caret_double_light=0x7f020027; - public static final int ic_email_caret_single_light=0x7f020028; - public static final int ic_email_thread_open_bottom_default=0x7f020029; - public static final int ic_email_thread_open_top_default=0x7f02002a; - public static final int ic_menu_account_list=0x7f02002b; - public static final int ic_menu_add=0x7f02002c; - public static final int ic_menu_archive=0x7f02002d; - public static final int ic_menu_attachment=0x7f02002e; - public static final int ic_menu_cc=0x7f02002f; - public static final int ic_menu_close_clear_cancel=0x7f020030; - public static final int ic_menu_compose=0x7f020031; - public static final int ic_menu_delete=0x7f020032; - public static final int ic_menu_edit=0x7f020033; - public static final int ic_menu_forward_mail=0x7f020034; - public static final int ic_menu_inbox=0x7f020035; - public static final int ic_menu_mark=0x7f020036; - public static final int ic_menu_navigate=0x7f020037; - public static final int ic_menu_preferences=0x7f020038; - public static final int ic_menu_refresh=0x7f020039; - public static final int ic_menu_reply=0x7f02003a; - public static final int ic_menu_reply_all=0x7f02003b; - public static final int ic_menu_save_draft=0x7f02003c; - public static final int ic_menu_search=0x7f02003d; - public static final int ic_menu_send=0x7f02003e; - public static final int ic_mms_attachment_small=0x7f02003f; - public static final int icon=0x7f020040; - public static final int stat_notify_email_generic=0x7f020041; - public static final int text_box=0x7f020042; - public static final int text_box_light=0x7f020043; - } - public static final class id { - public static final int account_always_bcc=0x7f0a000b; - public static final int account_check_frequency=0x7f0a0018; - public static final int account_default=0x7f0a0005; - public static final int account_delete_policy=0x7f0a0013; - public static final int account_delete_policy_label=0x7f0a0012; - public static final int account_description=0x7f0a0016; - public static final int account_email=0x7f0a0002; - public static final int account_name=0x7f0a000a; - public static final int account_notify=0x7f0a0019; - public static final int account_password=0x7f0a0003; - public static final int account_port=0x7f0a0010; - public static final int account_require_login=0x7f0a001a; - public static final int account_require_login_settings=0x7f0a001b; - public static final int account_security_type=0x7f0a0011; - public static final int account_server=0x7f0a000f; - public static final int account_server_label=0x7f0a000e; - public static final int account_settings=0x7f0a004e; - public static final int account_signature=0x7f0a000c; - public static final int account_username=0x7f0a000d; - public static final int accounts=0x7f0a004d; - public static final int add_attachment=0x7f0a0053; - public static final int add_cc_bcc=0x7f0a004f; - public static final int add_new_account=0x7f0a001d; - public static final int attachment=0x7f0a003d; - public static final int attachment_delete=0x7f0a0033; - public static final int attachment_icon=0x7f0a0039; - public static final int attachment_info=0x7f0a003a; - public static final int attachment_name=0x7f0a0034; - public static final int attachments=0x7f0a002e; - public static final int bcc=0x7f0a002d; - public static final int cancel=0x7f0a0009; - public static final int cc=0x7f0a002c; - public static final int check_mail=0x7f0a0047; - public static final int chip=0x7f0a0024; - public static final int compose=0x7f0a0048; - public static final int date=0x7f0a0026; - public static final int debug_logging=0x7f0a0022; - public static final int delete=0x7f0a0038; - public static final int delete_account=0x7f0a0046; - public static final int description=0x7f0a001e; - public static final int discard=0x7f0a0052; - public static final int done=0x7f0a0017; - public static final int download=0x7f0a003b; - public static final int dump_settings=0x7f0a0049; - public static final int edit_account=0x7f0a0045; - public static final int email=0x7f0a001f; - public static final int empty=0x7f0a001c; - public static final int folder_name=0x7f0a0029; - public static final int folder_status=0x7f0a002a; - public static final int forward=0x7f0a004a; - public static final int from=0x7f0a0025; - public static final int imap=0x7f0a0001; - public static final int imap_path_prefix=0x7f0a0015; - public static final int imap_path_prefix_section=0x7f0a0014; - public static final int main_text=0x7f0a0028; - public static final int manual_setup=0x7f0a0006; - public static final int mark_as_read=0x7f0a004b; - public static final int mark_as_unread=0x7f0a0054; - public static final int message=0x7f0a0007; - public static final int message_content=0x7f0a002f; - public static final int new_message_count=0x7f0a0020; - public static final int next=0x7f0a0004; - public static final int open=0x7f0a0044; - public static final int pop=0x7f0a0000; - public static final int previous=0x7f0a0035; - public static final int progress=0x7f0a0008; - public static final int quoted_text=0x7f0a0032; - public static final int quoted_text_bar=0x7f0a0030; - public static final int quoted_text_delete=0x7f0a0031; - public static final int refresh=0x7f0a004c; - public static final int reply=0x7f0a0036; - public static final int reply_all=0x7f0a0037; - public static final int save=0x7f0a0051; - public static final int send=0x7f0a0050; - public static final int sensitive_logging=0x7f0a0023; - public static final int show_pictures=0x7f0a0041; - public static final int show_pictures_section=0x7f0a0040; - public static final int subject=0x7f0a0027; - public static final int text1=0x7f0a0042; - public static final int text2=0x7f0a0043; - public static final int to=0x7f0a002b; - public static final int to_container=0x7f0a003e; - public static final int to_label=0x7f0a003f; - public static final int version=0x7f0a0021; - public static final int view=0x7f0a003c; - } - public static final class layout { - public static final int account_setup_account_type=0x7f030000; - public static final int account_setup_basics=0x7f030001; - public static final int account_setup_check_settings=0x7f030002; - public static final int account_setup_composition=0x7f030003; - public static final int account_setup_incoming=0x7f030004; - public static final int account_setup_names=0x7f030005; - public static final int account_setup_options=0x7f030006; - public static final int account_setup_outgoing=0x7f030007; - public static final int accounts=0x7f030008; - public static final int accounts_item=0x7f030009; - public static final int debug=0x7f03000a; - public static final int folder_message_list_child=0x7f03000b; - public static final int folder_message_list_child_footer=0x7f03000c; - public static final int folder_message_list_group=0x7f03000d; - public static final int message_compose=0x7f03000e; - public static final int message_compose_attachment=0x7f03000f; - public static final int message_view=0x7f030010; - public static final int message_view_attachment=0x7f030011; - public static final int message_view_header=0x7f030012; - public static final int recipient_dropdown_item=0x7f030013; - } - public static final class menu { - public static final int accounts_context=0x7f090000; - public static final int accounts_option=0x7f090001; - public static final int debug_option=0x7f090002; - public static final int folder_message_list_context=0x7f090003; - public static final int folder_message_list_option=0x7f090004; - public static final int message_compose_option=0x7f090005; - public static final int message_view_option=0x7f090006; - } - public static final class string { - public static final int account_delete_dlg_instructions_fmt=0x7f0600c8; - public static final int account_delete_dlg_title=0x7f0600c7; - public static final int account_settings_action=0x7f06001b; - public static final int account_settings_add_account_label=0x7f0600b9; - public static final int account_settings_always_bcc_label=0x7f0600c3; - public static final int account_settings_always_bcc_summary=0x7f0600c4; - public static final int account_settings_composition_label=0x7f0600c2; - public static final int account_settings_composition_title=0x7f0600c1; - public static final int account_settings_default=0x7f0600ad; - public static final int account_settings_default_label=0x7f0600ae; - public static final int account_settings_default_summary=0x7f0600af; - public static final int account_settings_description_label=0x7f0600ba; - public static final int account_settings_email_label=0x7f0600b1; - public static final int account_settings_incoming_label=0x7f0600b5; - public static final int account_settings_incoming_summary=0x7f0600b6; - public static final int account_settings_mail_check_frequency_label=0x7f0600b4; - public static final int account_settings_name_label=0x7f0600bb; - public static final int account_settings_notifications=0x7f0600bc; - public static final int account_settings_notify_label=0x7f0600b0; - public static final int account_settings_notify_summary=0x7f0600b2; - public static final int account_settings_outgoing_label=0x7f0600b7; - public static final int account_settings_outgoing_summary=0x7f0600b8; - public static final int account_settings_ringtone=0x7f0600bf; - public static final int account_settings_servers=0x7f0600c0; - public static final int account_settings_show_combined_label=0x7f0600b3; - public static final int account_settings_signature_label=0x7f0600c5; - public static final int account_settings_signature_summary=0x7f0600c6; - public static final int account_settings_title_fmt=0x7f0600ac; - public static final int account_settings_vibrate_enable=0x7f0600bd; - public static final int account_settings_vibrate_summary=0x7f0600be; - public static final int account_setup_account_type_imap_action=0x7f060079; - public static final int account_setup_account_type_instructions=0x7f060077; - public static final int account_setup_account_type_pop_action=0x7f060078; - public static final int account_setup_account_type_title=0x7f060076; - public static final int account_setup_basics_default_label=0x7f060069; - public static final int account_setup_basics_email_error_duplicate_fmt=0x7f060067; - public static final int account_setup_basics_email_error_invalid_fmt=0x7f060066; - public static final int account_setup_basics_email_hint=0x7f060065; - public static final int account_setup_basics_instructions=0x7f060063; - public static final int account_setup_basics_instructions2_fmt=0x7f060064; - public static final int account_setup_basics_manual_setup_action=0x7f06006a; - public static final int account_setup_basics_password_hint=0x7f060068; - public static final int account_setup_basics_title=0x7f060062; - public static final int account_setup_check_settings_canceling_msg=0x7f060070; - public static final int account_setup_check_settings_check_incoming_msg=0x7f06006d; - public static final int account_setup_check_settings_check_outgoing_msg=0x7f06006e; - public static final int account_setup_check_settings_finishing_msg=0x7f06006f; - public static final int account_setup_check_settings_retr_info_msg=0x7f06006c; - public static final int account_setup_check_settings_title=0x7f06006b; - public static final int account_setup_failed_dlg_auth_message_fmt=0x7f0600a8; - /** Username or password incorrect\n(ERR01 Account does not exist) - */ - public static final int account_setup_failed_dlg_certificate_message_fmt=0x7f0600a9; - /** Cannot connect to server\n(Connection timed out) - */ - public static final int account_setup_failed_dlg_edit_details_action=0x7f0600ab; - /** Cannot safely connect to server\n(Invalid certificate) - */ - public static final int account_setup_failed_dlg_server_message_fmt=0x7f0600aa; - public static final int account_setup_failed_dlg_title=0x7f0600a7; - public static final int account_setup_finished_toast=0x7f060075; - public static final int account_setup_incoming_delete_policy_7days_label=0x7f060088; - public static final int account_setup_incoming_delete_policy_delete_label=0x7f060089; - public static final int account_setup_incoming_delete_policy_label=0x7f060086; - public static final int account_setup_incoming_delete_policy_never_label=0x7f060087; - public static final int account_setup_incoming_imap_path_prefix_hint=0x7f06008b; - public static final int account_setup_incoming_imap_path_prefix_label=0x7f06008a; - public static final int account_setup_incoming_imap_server_label=0x7f06007e; - public static final int account_setup_incoming_password_label=0x7f06007c; - public static final int account_setup_incoming_pop_server_label=0x7f06007d; - public static final int account_setup_incoming_port_label=0x7f06007f; - public static final int account_setup_incoming_security_label=0x7f060080; - public static final int account_setup_incoming_security_none_label=0x7f060081; - public static final int account_setup_incoming_security_ssl_label=0x7f060083; - public static final int account_setup_incoming_security_ssl_optional_label=0x7f060082; - public static final int account_setup_incoming_security_tls_label=0x7f060085; - public static final int account_setup_incoming_security_tls_optional_label=0x7f060084; - public static final int account_setup_incoming_title=0x7f06007a; - public static final int account_setup_incoming_username_label=0x7f06007b; - public static final int account_setup_names_account_name_label=0x7f060073; - public static final int account_setup_names_instructions=0x7f060072; - public static final int account_setup_names_title=0x7f060071; - public static final int account_setup_names_user_name_label=0x7f060074; - public static final int account_setup_options_default_label=0x7f0600a5; - public static final int account_setup_options_mail_check_frequency_10min=0x7f0600a1; - public static final int account_setup_options_mail_check_frequency_15min=0x7f0600a2; - public static final int account_setup_options_mail_check_frequency_1hour=0x7f0600a4; - public static final int account_setup_options_mail_check_frequency_30min=0x7f0600a3; - public static final int account_setup_options_mail_check_frequency_5min=0x7f0600a0; - public static final int account_setup_options_mail_check_frequency_label=0x7f06009e; - /** Frequency also used in account_settings_* - */ - public static final int account_setup_options_mail_check_frequency_never=0x7f06009f; - public static final int account_setup_options_notify_label=0x7f0600a6; - public static final int account_setup_options_title=0x7f06009d; - public static final int account_setup_outgoing_authentication_basic_label=0x7f060098; - public static final int account_setup_outgoing_authentication_basic_password_label=0x7f06009a; - public static final int account_setup_outgoing_authentication_basic_username_label=0x7f060099; - public static final int account_setup_outgoing_authentication_imap_before_smtp_label=0x7f06009c; - /** The authentication strings below are for a planned (hopefully) change to the above username and password options - */ - public static final int account_setup_outgoing_authentication_label=0x7f060097; - public static final int account_setup_outgoing_authentication_pop_before_smtp_label=0x7f06009b; - public static final int account_setup_outgoing_password_label=0x7f060096; - public static final int account_setup_outgoing_port_label=0x7f06008e; - public static final int account_setup_outgoing_require_login_label=0x7f060094; - public static final int account_setup_outgoing_security_label=0x7f06008f; - public static final int account_setup_outgoing_security_none_label=0x7f060090; - public static final int account_setup_outgoing_security_ssl_label=0x7f060091; - public static final int account_setup_outgoing_security_tls_label=0x7f060093; - public static final int account_setup_outgoing_security_tls_optional_label=0x7f060092; - public static final int account_setup_outgoing_smtp_server_label=0x7f06008d; - public static final int account_setup_outgoing_title=0x7f06008c; - public static final int account_setup_outgoing_username_label=0x7f060095; - public static final int accounts_action=0x7f06001d; - public static final int accounts_context_menu_title=0x7f060029; - public static final int accounts_title=0x7f060004; - public static final int accounts_welcome=0x7f06003b; - public static final int add_account_action=0x7f060016; - public static final int add_attachment_action=0x7f060026; - public static final int add_cc_bcc_action=0x7f060024; - public static final int app_name=0x7f060003; - public static final int build_number=0x7f060000; - /** User to confirm acceptance of dialog boxes, warnings, errors, etc. - */ - public static final int cancel_action=0x7f060009; - public static final int combined_inbox_label=0x7f060041; - public static final int combined_inbox_list_title=0x7f060042; - public static final int combined_inbox_title=0x7f060040; - public static final int compose_action=0x7f060017; - public static final int compose_title=0x7f060005; - public static final int continue_action=0x7f06000f; - public static final int debug_enable_debug_logging_label=0x7f06003d; - public static final int debug_enable_sensitive_logging_label=0x7f06003e; - public static final int debug_title=0x7f060006; - public static final int debug_version_fmt=0x7f06003c; - public static final int delete_action=0x7f06000d; - public static final int discard_action=0x7f060012; - public static final int done_action=0x7f060010; - public static final int dump_settings_action=0x7f060027; - public static final int edit_subject_action=0x7f060025; - public static final int empty_trash_action=0x7f060028; - public static final int folders_action=0x7f060022; - public static final int forward_action=0x7f06000e; - public static final int general_no_subject=0x7f06002a; - public static final int mailbox_select_dlg_new_mailbox_action=0x7f06005b; - public static final int mailbox_select_dlg_title=0x7f06005a; - public static final int mark_as_read_action=0x7f06001f; - public static final int mark_as_unread_action=0x7f060020; - public static final int message_compose_attachments_skipped_toast=0x7f06004e; - public static final int message_compose_bcc_hint=0x7f060047; - public static final int message_compose_cc_hint=0x7f060046; - public static final int message_compose_downloading_attachments_toast=0x7f06004d; - public static final int message_compose_error_no_recipients=0x7f06004c; - public static final int message_compose_fwd_header_fmt=0x7f060049; - public static final int message_compose_quoted_text_label=0x7f06004b; - public static final int message_compose_reply_header_fmt=0x7f06004a; - public static final int message_compose_subject_hint=0x7f060048; - public static final int message_compose_to_hint=0x7f060045; - public static final int message_copied_toast=0x7f06005d; - public static final int message_deleted_toast=0x7f06005f; - public static final int message_discarded_toast=0x7f060060; - public static final int message_header_mua=0x7f06003f; - /** Inbox (12) - */ - public static final int message_list_load_more_messages_action=0x7f060044; - /** Inbox here should be the same as mailbox_name_inbox - */ - public static final int message_list_title_fmt=0x7f060043; - public static final int message_moved_toast=0x7f06005e; - public static final int message_saved_toast=0x7f060061; - public static final int message_view_attachment_download_action=0x7f060051; - public static final int message_view_attachment_view_action=0x7f060050; - public static final int message_view_datetime_fmt=0x7f060054; - public static final int message_view_fetching_attachment_toast=0x7f060059; - public static final int message_view_next_action=0x7f060053; - public static final int message_view_prev_action=0x7f060052; - public static final int message_view_show_pictures_action=0x7f060058; - public static final int message_view_show_pictures_instructions=0x7f060057; - public static final int message_view_status_attachment_not_saved=0x7f060056; - public static final int message_view_status_attachment_saved=0x7f060055; - public static final int message_view_to_label=0x7f06004f; - public static final int move_to_action=0x7f060021; - public static final int new_mailbox_dlg_title=0x7f06005c; - /** Actions will be used as buttons and in menu items - */ - public static final int next_action=0x7f060007; - /** 279 Unread (someone@google.com) - */ - public static final int notification_new_multi_account_fmt=0x7f060034; - public static final int notification_new_one_account_fmt=0x7f060033; - public static final int notification_new_scrolling=0x7f060032; - public static final int notification_new_title=0x7f060031; - public static final int notification_unsent_title=0x7f060035; - /** Used as part of a multi-step process - */ - public static final int okay_action=0x7f060008; - public static final int open_action=0x7f06001a; - public static final int preferences_action=0x7f060019; - public static final int provider_note_live=0x7f0600ca; - public static final int provider_note_yahoo=0x7f0600c9; - public static final int read_action=0x7f06001e; - public static final int read_attachment_desc=0x7f060002; - public static final int read_attachment_label=0x7f060001; - public static final int refresh_action=0x7f060015; - public static final int remove_account_action=0x7f06001c; - /** Used to complete a multi-step process - */ - public static final int remove_action=0x7f060011; - public static final int reply_action=0x7f06000b; - public static final int reply_all_action=0x7f06000c; - public static final int retry_action=0x7f060014; - public static final int save_draft_action=0x7f060013; - public static final int search_action=0x7f060018; - public static final int send_action=0x7f06000a; - /** The following mailbox names will be used if the user has not specified one from the server - */ - public static final int special_mailbox_name_drafts=0x7f060038; - public static final int special_mailbox_name_inbox=0x7f060036; - public static final int special_mailbox_name_outbox=0x7f060037; - public static final int special_mailbox_name_sent=0x7f06003a; - public static final int special_mailbox_name_trash=0x7f060039; - public static final int status_error=0x7f06002e; - /** Shown in place of the subject when a message has no subject. Showing this in parentheses is customary. - */ - public static final int status_loading=0x7f06002b; - public static final int status_loading_more=0x7f06002c; - /** Used in Outbox when a message is currently sending - */ - public static final int status_loading_more_failed=0x7f060030; - public static final int status_network_error=0x7f06002d; - /** Used in Outbox when a message has failed to send - */ - public static final int status_sending=0x7f06002f; - public static final int view_hide_details_action=0x7f060023; - } - public static final class xml { - public static final int account_settings_preferences=0x7f040000; - public static final int providers=0x7f040001; - } -} diff --git a/src/com/fsck/k9/Utility.java b/src/com/fsck/k9/Utility.java deleted file mode 100644 index 08f643f3b..000000000 --- a/src/com/fsck/k9/Utility.java +++ /dev/null @@ -1,176 +0,0 @@ - -package com.fsck.k9; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.util.Date; - -import com.fsck.k9.codec.binary.Base64; - -import android.text.Editable; -import android.widget.TextView; - -public class Utility { - public final static String readInputStream(InputStream in, String encoding) throws IOException { - InputStreamReader reader = new InputStreamReader(in, encoding); - StringBuffer sb = new StringBuffer(); - int count; - char[] buf = new char[512]; - while ((count = reader.read(buf)) != -1) { - sb.append(buf, 0, count); - } - return sb.toString(); - } - - public final static boolean arrayContains(Object[] a, Object o) { - for (int i = 0, count = a.length; i < count; i++) { - if (a[i].equals(o)) { - return true; - } - } - return false; - } - - /** - * Combines the given array of Objects into a single string using the - * seperator character and each Object's toString() method. between each - * part. - * - * @param parts - * @param seperator - * @return - */ - public static String combine(Object[] parts, char seperator) { - if (parts == null) { - return null; - } - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < parts.length; i++) { - sb.append(parts[i].toString()); - if (i < parts.length - 1) { - sb.append(seperator); - } - } - return sb.toString(); - } - - public static String base64Decode(String encoded) { - if (encoded == null) { - return null; - } - byte[] decoded = new Base64().decode(encoded.getBytes()); - return new String(decoded); - } - - public static String base64Encode(String s) { - if (s == null) { - return s; - } - byte[] encoded = new Base64().encode(s.getBytes()); - return new String(encoded); - } - - public static boolean requiredFieldValid(TextView view) { - return view.getText() != null && view.getText().length() > 0; - } - - public static boolean requiredFieldValid(Editable s) { - return s != null && s.length() > 0; - } - - /** - * Ensures that the given string starts and ends with the double quote character. The string is not modified in any way except to add the - * double quote character to start and end if it's not already there. - * sample -> "sample" - * "sample" -> "sample" - * ""sample"" -> "sample" - * "sample"" -> "sample" - * sa"mp"le -> "sa"mp"le" - * "sa"mp"le" -> "sa"mp"le" - * (empty string) -> "" - * " -> "" - * @param s - * @return - */ - public static String quoteString(String s) { - if (s == null) { - return null; - } - if (!s.matches("^\".*\"$")) { - return "\"" + s + "\""; - } - else { - return s; - } - } - - /** - * A fast version of URLDecoder.decode() that works only with UTF-8 and does only two - * allocations. This version is around 3x as fast as the standard one and I'm using it - * hundreds of times in places that slow down the UI, so it helps. - */ - public static String fastUrlDecode(String s) { - try { - byte[] bytes = s.getBytes("UTF-8"); - byte ch; - int length = 0; - for (int i = 0, count = bytes.length; i < count; i++) { - ch = bytes[i]; - if (ch == '%') { - int h = (bytes[i + 1] - '0'); - int l = (bytes[i + 2] - '0'); - if (h > 9) { - h -= 7; - } - if (l > 9) { - l -= 7; - } - bytes[length] = (byte) ((h << 4) | l); - i += 2; - } - else if (ch == '+') { - bytes[length] = ' '; - } - else { - bytes[length] = bytes[i]; - } - length++; - } - return new String(bytes, 0, length, "UTF-8"); - } - catch (UnsupportedEncodingException uee) { - return null; - } - } - - /** - * Returns true if the specified date is within today. Returns false otherwise. - * @param date - * @return - */ - public static boolean isDateToday(Date date) { - // TODO But Calendar is so slowwwwwww.... - Date today = new Date(); - if (date.getYear() == today.getYear() && - date.getMonth() == today.getMonth() && - date.getDate() == today.getDate()) { - return true; - } - return false; - } - - /* - * TODO disabled this method globally. It is used in all the settings screens but I just - * noticed that an unrelated icon was dimmed. Android must share drawables internally. - */ - public static void setCompoundDrawablesAlpha(TextView view, int alpha) { -// Drawable[] drawables = view.getCompoundDrawables(); -// for (Drawable drawable : drawables) { -// if (drawable != null) { -// drawable.setAlpha(alpha); -// } -// } - } -} diff --git a/src/com/fsck/k9/activity/Accounts.java b/src/com/fsck/k9/activity/Accounts.java deleted file mode 100644 index 3010eaf20..000000000 --- a/src/com/fsck/k9/activity/Accounts.java +++ /dev/null @@ -1,296 +0,0 @@ - -package com.fsck.k9.activity; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ListActivity; -import android.app.NotificationManager; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.View.OnClickListener; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.AdapterView.OnItemClickListener; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.MessagingController; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; -import com.fsck.k9.activity.setup.AccountSettings; -import com.fsck.k9.activity.setup.AccountSetupBasics; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.store.LocalStore; -import com.fsck.k9.mail.store.LocalStore.LocalFolder; - -public class Accounts extends ListActivity implements OnItemClickListener, OnClickListener { - private static final int DIALOG_REMOVE_ACCOUNT = 1; - /** - * Key codes used to open a debug settings screen. - */ - private static int[] secretKeyCodes = { - KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_U, - KeyEvent.KEYCODE_G - }; - - private int mSecretKeyCodeIndex = 0; - private Account mSelectedContextAccount; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.accounts); - ListView listView = getListView(); - listView.setOnItemClickListener(this); - listView.setItemsCanFocus(false); - listView.setEmptyView(findViewById(R.id.empty)); - findViewById(R.id.add_new_account).setOnClickListener(this); - registerForContextMenu(listView); - - if (icicle != null && icicle.containsKey("selectedContextAccount")) { - mSelectedContextAccount = (Account) icicle.getSerializable("selectedContextAccount"); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (mSelectedContextAccount != null) { - outState.putSerializable("selectedContextAccount", mSelectedContextAccount); - } - } - - @Override - public void onResume() { - super.onResume(); - - NotificationManager notifMgr = (NotificationManager) - getSystemService(Context.NOTIFICATION_SERVICE); - notifMgr.cancel(1); - - refresh(); - } - - private void refresh() { - Account[] accounts = Preferences.getPreferences(this).getAccounts(); - getListView().setAdapter(new AccountsAdapter(accounts)); - } - - private void onAddNewAccount() { - AccountSetupBasics.actionNewAccount(this); - } - - private void onEditAccount(Account account) { - AccountSettings.actionSettings(this, account); - } - - private void onRefresh() { - MessagingController.getInstance(getApplication()).checkMail(this, null, null); - } - - private void onCompose() { - Account defaultAccount = - Preferences.getPreferences(this).getDefaultAccount(); - if (defaultAccount != null) { - MessageCompose.actionCompose(this, defaultAccount); - } - else { - onAddNewAccount(); - } - } - - private void onOpenAccount(Account account) { - FolderMessageList.actionHandleAccount(this, account); - } - - public void onClick(View view) { - if (view.getId() == R.id.add_new_account) { - onAddNewAccount(); - } - } - - private void onDeleteAccount(Account account) { - mSelectedContextAccount = account; - showDialog(DIALOG_REMOVE_ACCOUNT); - } - - @Override - public Dialog onCreateDialog(int id) { - switch (id) { - case DIALOG_REMOVE_ACCOUNT: - return createRemoveAccountDialog(); - } - return super.onCreateDialog(id); - } - - private Dialog createRemoveAccountDialog() { - return new AlertDialog.Builder(this) - .setTitle(R.string.account_delete_dlg_title) - .setMessage(getString(R.string.account_delete_dlg_instructions_fmt, - mSelectedContextAccount.getDescription())) - .setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - dismissDialog(DIALOG_REMOVE_ACCOUNT); - try { - ((LocalStore)Store.getInstance( - mSelectedContextAccount.getLocalStoreUri(), - getApplication())).delete(); - } catch (Exception e) { - // Ignore - } - mSelectedContextAccount.delete(Preferences.getPreferences(Accounts.this)); - k9.setServicesEnabled(Accounts.this); - refresh(); - } - }) - .setNegativeButton(R.string.cancel_action, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - dismissDialog(DIALOG_REMOVE_ACCOUNT); - } - }) - .create(); - } - - public boolean onContextItemSelected(MenuItem item) { - AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)item.getMenuInfo(); - Account account = (Account)getListView().getItemAtPosition(menuInfo.position); - switch (item.getItemId()) { - case R.id.delete_account: - onDeleteAccount(account); - break; - case R.id.edit_account: - onEditAccount(account); - break; - case R.id.open: - onOpenAccount(account); - break; - } - return true; - } - - public void onItemClick(AdapterView parent, View view, int position, long id) { - Account account = (Account)parent.getItemAtPosition(position); - onOpenAccount(account); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.add_new_account: - onAddNewAccount(); - break; - case R.id.check_mail: - onRefresh(); - break; - case R.id.compose: - onCompose(); - break; - default: - return super.onOptionsItemSelected(item); - } - return true; - } - - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - return true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.accounts_option, menu); - return true; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - menu.setHeaderTitle(R.string.accounts_context_menu_title); - getMenuInflater().inflate(R.menu.accounts_context, menu); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (event.getKeyCode() == secretKeyCodes[mSecretKeyCodeIndex]) { - mSecretKeyCodeIndex++; - if (mSecretKeyCodeIndex == secretKeyCodes.length) { - mSecretKeyCodeIndex = 0; - startActivity(new Intent(this, Debug.class)); - } - } else { - mSecretKeyCodeIndex = 0; - } - return super.onKeyDown(keyCode, event); - } - - class AccountsAdapter extends ArrayAdapter { - public AccountsAdapter(Account[] accounts) { - super(Accounts.this, 0, accounts); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Account account = getItem(position); - View view; - if (convertView != null) { - view = convertView; - } - else { - view = getLayoutInflater().inflate(R.layout.accounts_item, parent, false); - } - AccountViewHolder holder = (AccountViewHolder) view.getTag(); - if (holder == null) { - holder = new AccountViewHolder(); - holder.description = (TextView) view.findViewById(R.id.description); - holder.email = (TextView) view.findViewById(R.id.email); - holder.newMessageCount = (TextView) view.findViewById(R.id.new_message_count); - view.setTag(holder); - } - holder.description.setText(account.getDescription()); - holder.email.setText(account.getEmail()); - if (account.getEmail().equals(account.getDescription())) { - holder.email.setVisibility(View.GONE); - } - int unreadMessageCount = 0; - try { - LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - getApplication()); - LocalFolder localFolder = (LocalFolder) localStore.getFolder(k9.INBOX); - if (localFolder.exists()) { - unreadMessageCount = localFolder.getUnreadMessageCount(); - } - } - catch (MessagingException me) { - /* - * This is not expected to fail under normal circumstances. - */ - throw new RuntimeException("Unable to get unread count from local store.", me); - } - holder.newMessageCount.setText(Integer.toString(unreadMessageCount)); - holder.newMessageCount.setVisibility(unreadMessageCount > 0 ? View.VISIBLE : View.GONE); - return view; - } - - class AccountViewHolder { - public TextView description; - public TextView email; - public TextView newMessageCount; - } - } -} - - diff --git a/src/com/fsck/k9/activity/Debug.java b/src/com/fsck/k9/activity/Debug.java deleted file mode 100644 index 8c4c51809..000000000 --- a/src/com/fsck/k9/activity/Debug.java +++ /dev/null @@ -1,73 +0,0 @@ - -package com.fsck.k9.activity; - -import android.app.Activity; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.TextView; -import android.widget.CompoundButton.OnCheckedChangeListener; - -import com.fsck.k9.k9; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; - -public class Debug extends Activity implements OnCheckedChangeListener { - private TextView mVersionView; - private CheckBox mEnableDebugLoggingView; - private CheckBox mEnableSensitiveLoggingView; - - private Preferences mPreferences; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.debug); - - mPreferences = Preferences.getPreferences(this); - - mVersionView = (TextView)findViewById(R.id.version); - mEnableDebugLoggingView = (CheckBox)findViewById(R.id.debug_logging); - mEnableSensitiveLoggingView = (CheckBox)findViewById(R.id.sensitive_logging); - - mEnableDebugLoggingView.setOnCheckedChangeListener(this); - mEnableSensitiveLoggingView.setOnCheckedChangeListener(this); - - mVersionView.setText(String.format(getString(R.string.debug_version_fmt).toString(), - getString(R.string.build_number))); - - mEnableDebugLoggingView.setChecked(k9.DEBUG); - mEnableSensitiveLoggingView.setChecked(k9.DEBUG_SENSITIVE); - } - - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (buttonView.getId() == R.id.debug_logging) { - k9.DEBUG = isChecked; - mPreferences.setEnableDebugLogging(k9.DEBUG); - } else if (buttonView.getId() == R.id.sensitive_logging) { - k9.DEBUG_SENSITIVE = isChecked; - mPreferences.setEnableSensitiveLogging(k9.DEBUG_SENSITIVE); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == R.id.dump_settings) { - Preferences.getPreferences(this).dump(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.debug_option, menu); - return true; - } - -} diff --git a/src/com/fsck/k9/activity/FolderMessageList.java b/src/com/fsck/k9/activity/FolderMessageList.java deleted file mode 100644 index 5642bedce..000000000 --- a/src/com/fsck/k9/activity/FolderMessageList.java +++ /dev/null @@ -1,1283 +0,0 @@ -package com.fsck.k9.activity; - -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; - -import android.app.ExpandableListActivity; -import android.app.NotificationManager; -import android.content.Context; -import android.content.Intent; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.os.Process; -import android.util.Config; -import android.util.Log; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.ContextMenu.ContextMenuInfo; -import android.widget.BaseExpandableListAdapter; -import android.widget.ExpandableListView; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.ExpandableListView.ExpandableListContextMenuInfo; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.MessagingController; -import com.fsck.k9.MessagingListener; -import com.fsck.k9.R; -import com.fsck.k9.Utility; -import com.fsck.k9.Preferences; -import com.fsck.k9.activity.FolderMessageList.FolderMessageListAdapter.FolderInfoHolder; -import com.fsck.k9.activity.FolderMessageList.FolderMessageListAdapter.MessageInfoHolder; -import com.fsck.k9.activity.setup.AccountSettings; -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.Flag; -import com.fsck.k9.mail.Folder; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.store.LocalStore.LocalMessage; -import com.fsck.k9.mail.store.LocalStore; - -/** - * FolderMessageList is the primary user interface for the program. This Activity shows - * a two level list of the Account's folders and each folder's messages. From this - * Activity the user can perform all standard message operations. - * - * - * TODO some things that are slowing us down: - * Need a way to remove state such as progress bar and per folder progress on - * resume if the command has completed. - * - * TODO - * Break out seperate functions for: - * refresh local folders - * refresh remote folders - * refresh open folder local messages - * refresh open folder remote messages - * - * And don't refresh remote folders ever unless the user runs a refresh. Maybe not even then. - */ -public class FolderMessageList extends ExpandableListActivity { - private static final String EXTRA_ACCOUNT = "account"; - private static final String EXTRA_CLEAR_NOTIFICATION = "clearNotification"; - private static final String EXTRA_INITIAL_FOLDER = "initialFolder"; - - private static final String STATE_KEY_LIST = - "com.fsck.k9.activity.folderlist_expandableListState"; - private static final String STATE_KEY_EXPANDED_GROUP = - "com.fsck.k9.activity.folderlist_expandedGroup"; - private static final String STATE_KEY_EXPANDED_GROUP_SELECTION = - "com.fsck.k9.activity.folderlist_expandedGroupSelection"; - - private static final int UPDATE_FOLDER_ON_EXPAND_INTERVAL_MS = (1000 * 60 * 3); - - private static final int[] colorChipResIds = new int[] { - R.drawable.appointment_indicator_leftside_1, - R.drawable.appointment_indicator_leftside_2, - R.drawable.appointment_indicator_leftside_3, - R.drawable.appointment_indicator_leftside_4, - R.drawable.appointment_indicator_leftside_5, - R.drawable.appointment_indicator_leftside_6, - R.drawable.appointment_indicator_leftside_7, - R.drawable.appointment_indicator_leftside_8, - R.drawable.appointment_indicator_leftside_9, - R.drawable.appointment_indicator_leftside_10, - R.drawable.appointment_indicator_leftside_11, - R.drawable.appointment_indicator_leftside_12, - R.drawable.appointment_indicator_leftside_13, - R.drawable.appointment_indicator_leftside_14, - R.drawable.appointment_indicator_leftside_15, - R.drawable.appointment_indicator_leftside_16, - R.drawable.appointment_indicator_leftside_17, - R.drawable.appointment_indicator_leftside_18, - R.drawable.appointment_indicator_leftside_19, - R.drawable.appointment_indicator_leftside_20, - R.drawable.appointment_indicator_leftside_21, - }; - - private ExpandableListView mListView; - private int colorChipResId; - - private FolderMessageListAdapter mAdapter; - private LayoutInflater mInflater; - private Account mAccount; - /** - * Stores the name of the folder that we want to open as soon as possible after load. It is - * set to null once the folder has been opened once. - */ - private String mInitialFolder; - - private DateFormat mDateFormat = DateFormat.getDateInstance(DateFormat.SHORT); - private DateFormat mTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT); - - private int mExpandedGroup = -1; - private boolean mRestoringState; - - private boolean mRefreshRemote; - - private FolderMessageListHandler mHandler = new FolderMessageListHandler(); - - class FolderMessageListHandler extends Handler { - private static final int MSG_PROGRESS = 2; - private static final int MSG_DATA_CHANGED = 3; - private static final int MSG_EXPAND_GROUP = 5; - private static final int MSG_FOLDER_LOADING = 7; - private static final int MSG_REMOVE_MESSAGE = 11; - private static final int MSG_SYNC_MESSAGES = 13; - private static final int MSG_FOLDER_STATUS = 17; - - @Override - public void handleMessage(android.os.Message msg) { - switch (msg.what) { - case MSG_PROGRESS: - setProgressBarIndeterminateVisibility(msg.arg1 != 0); - break; - case MSG_DATA_CHANGED: - mAdapter.notifyDataSetChanged(); - break; - case MSG_EXPAND_GROUP: - mListView.expandGroup(msg.arg1); - break; - /* - * The following functions modify the state of the adapter's underlying list and - * must be run here, in the main thread, so that notifyDataSetChanged is run - * before any further requests are made to the adapter. - */ - case MSG_FOLDER_LOADING: { - FolderInfoHolder folder = mAdapter.getFolder((String) msg.obj); - if (folder != null) { - folder.loading = msg.arg1 != 0; - mAdapter.notifyDataSetChanged(); - } - break; - } - case MSG_REMOVE_MESSAGE: { - FolderInfoHolder folder = (FolderInfoHolder) ((Object[]) msg.obj)[0]; - MessageInfoHolder message = (MessageInfoHolder) ((Object[]) msg.obj)[1]; - folder.messages.remove(message); - mAdapter.notifyDataSetChanged(); - break; - } - case MSG_SYNC_MESSAGES: { - FolderInfoHolder folder = (FolderInfoHolder) ((Object[]) msg.obj)[0]; - Message[] messages = (Message[]) ((Object[]) msg.obj)[1]; - folder.messages.clear(); - for (Message message : messages) { - mAdapter.addOrUpdateMessage(folder, message, false, false); - } - Collections.sort(folder.messages); - mAdapter.notifyDataSetChanged(); - break; - } - case MSG_FOLDER_STATUS: { - String folderName = (String) ((Object[]) msg.obj)[0]; - String status = (String) ((Object[]) msg.obj)[1]; - FolderInfoHolder folder = mAdapter.getFolder(folderName); - if (folder != null) { - folder.status = status; - mAdapter.notifyDataSetChanged(); - } - break; - } - default: - super.handleMessage(msg); - } - } - - public void synchronizeMessages(FolderInfoHolder folder, Message[] messages) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_SYNC_MESSAGES; - msg.obj = new Object[] { folder, messages }; - sendMessage(msg); - } - - public void removeMessage(FolderInfoHolder folder, MessageInfoHolder message) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_REMOVE_MESSAGE; - msg.obj = new Object[] { folder, message }; - sendMessage(msg); - } - - public void folderLoading(String folder, boolean loading) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_FOLDER_LOADING; - msg.arg1 = loading ? 1 : 0; - msg.obj = folder; - sendMessage(msg); - } - - public void progress(boolean progress) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_PROGRESS; - msg.arg1 = progress ? 1 : 0; - sendMessage(msg); - } - - public void dataChanged() { - sendEmptyMessage(MSG_DATA_CHANGED); - } - - public void expandGroup(int groupPosition) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_EXPAND_GROUP; - msg.arg1 = groupPosition; - sendMessage(msg); - } - - public void folderStatus(String folder, String status) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_FOLDER_STATUS; - msg.obj = new String[] { folder, status }; - sendMessage(msg); - } - } - - /** - * This class is responsible for reloading the list of local messages for a given folder, - * notifying the adapter that the message have been loaded and queueing up a remote - * update of the folder. - */ - class FolderUpdateWorker implements Runnable { - String mFolder; - boolean mSynchronizeRemote; - - /** - * Create a worker for the given folder and specifying whether the - * worker should synchronize the remote folder or just the local one. - * @param folder - * @param synchronizeRemote - */ - public FolderUpdateWorker(String folder, boolean synchronizeRemote) { - mFolder = folder; - mSynchronizeRemote = synchronizeRemote; - } - - public void run() { - // Lower our priority - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - // Synchronously load the list of local messages - MessagingController.getInstance(getApplication()).listLocalMessages( - mAccount, - mFolder, - mAdapter.mListener); - if (mSynchronizeRemote) { - // Tell the MessagingController to run a remote update of this folder - // at it's leisure - MessagingController.getInstance(getApplication()).synchronizeMailbox( - mAccount, - mFolder, - mAdapter.mListener); - } - } - } - - public static void actionHandleAccount(Context context, Account account, String initialFolder) { - Intent intent = new Intent(context, FolderMessageList.class); - intent.putExtra(EXTRA_ACCOUNT, account); - if (initialFolder != null) { - intent.putExtra(EXTRA_INITIAL_FOLDER, initialFolder); - } - context.startActivity(intent); - } - - public static void actionHandleAccount(Context context, Account account) { - actionHandleAccount(context, account, null); - } - - public static Intent actionHandleAccountIntent(Context context, Account account, String initialFolder) { - Intent intent = new Intent(context, FolderMessageList.class); - intent.putExtra(EXTRA_ACCOUNT, account); - intent.putExtra(EXTRA_CLEAR_NOTIFICATION, true); - if (initialFolder != null) { - intent.putExtra(EXTRA_INITIAL_FOLDER, initialFolder); - } - return intent; - } - - public static Intent actionHandleAccountIntent(Context context, Account account) { - return actionHandleAccountIntent(context, account, null); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - - mListView = getExpandableListView(); - mListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET); - mListView.setLongClickable(true); - registerForContextMenu(mListView); - - /* - * We manually save and restore the list's state because our adapter is slow. - */ - mListView.setSaveEnabled(false); - - getExpandableListView().setGroupIndicator( - getResources().getDrawable(R.drawable.expander_ic_folder)); - - mInflater = getLayoutInflater(); - - Intent intent = getIntent(); - mAccount = (Account)intent.getSerializableExtra(EXTRA_ACCOUNT); - - // Take the initial folder into account only if we are *not* restoring the activity already - if (savedInstanceState == null) { - mInitialFolder = intent.getStringExtra(EXTRA_INITIAL_FOLDER); - } - - /* - * Since the color chip is always the same color for a given account we just cache the id - * of the chip right here. - */ - colorChipResId = colorChipResIds[mAccount.getAccountNumber() % colorChipResIds.length]; - - mAdapter = new FolderMessageListAdapter(); - - final Object previousData = getLastNonConfigurationInstance(); - if (previousData != null) { - //noinspection unchecked - mAdapter.mFolders = (ArrayList) previousData; - } - - setListAdapter(mAdapter); - - if (savedInstanceState != null) { - mRestoringState = true; - onRestoreListState(savedInstanceState); - mRestoringState = false; - } - - setTitle(mAccount.getDescription()); - } - - private void onRestoreListState(Bundle savedInstanceState) { - final int expandedGroup = savedInstanceState.getInt(STATE_KEY_EXPANDED_GROUP, -1); - if (expandedGroup >= 0 && mAdapter.getGroupCount() > expandedGroup) { - mListView.expandGroup(expandedGroup); - long selectedChild = savedInstanceState.getLong(STATE_KEY_EXPANDED_GROUP_SELECTION, -1); - if (selectedChild != ExpandableListView.PACKED_POSITION_VALUE_NULL) { - mListView.setSelection(mListView.getFlatListPosition(selectedChild)); - } - } - mListView.onRestoreInstanceState(savedInstanceState.getParcelable(STATE_KEY_LIST)); - } - - @Override - public Object onRetainNonConfigurationInstance() { - return mAdapter.mFolders; - } - - @Override - public void onPause() { - super.onPause(); - MessagingController.getInstance(getApplication()).removeListener(mAdapter.mListener); - } - - /** - * On resume we refresh the folder list (in the background) and we refresh the messages - * for any folder that is currently open. This guarantees that things like unread message - * count and read status are updated. - */ - @Override - public void onResume() { - super.onResume(); - - NotificationManager notifMgr = (NotificationManager) - getSystemService(Context.NOTIFICATION_SERVICE); - notifMgr.cancel(1); - - MessagingController.getInstance(getApplication()).addListener(mAdapter.mListener); - mAccount.refresh(Preferences.getPreferences(this)); - onRefresh(false); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putParcelable(STATE_KEY_LIST, mListView.onSaveInstanceState()); - outState.putInt(STATE_KEY_EXPANDED_GROUP, mExpandedGroup); - outState.putLong(STATE_KEY_EXPANDED_GROUP_SELECTION, mListView.getSelectedPosition()); - } - - @Override - public void onGroupCollapse(int groupPosition) { - super.onGroupCollapse(groupPosition); - mExpandedGroup = -1; - } - - @Override - public void onGroupExpand(int groupPosition) { - super.onGroupExpand(groupPosition); - if (mExpandedGroup != -1) { - mListView.collapseGroup(mExpandedGroup); - } - mExpandedGroup = groupPosition; - - if (!mRestoringState) { - /* - * Scroll the selected item to the top of the screen. - */ - int position = mListView.getFlatListPosition( - ExpandableListView.getPackedPositionForGroup(groupPosition)); - mListView.setSelectionFromTop(position, 0); - } - - final FolderInfoHolder folder = (FolderInfoHolder) mAdapter.getGroup(groupPosition); - /* - * We'll only do a hard refresh of a particular folder every 3 minutes or if the user - * specifically asks for a refresh. - */ - if (System.currentTimeMillis() - folder.lastChecked - > UPDATE_FOLDER_ON_EXPAND_INTERVAL_MS) { - folder.lastChecked = System.currentTimeMillis(); - // TODO: If the previous thread is already running, we should cancel it - new Thread(new FolderUpdateWorker(folder.name, true)).start(); - } - } - - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - int group = mListView.getPackedPositionGroup(mListView.getSelectedId()); - int item =(mListView.getSelectedItemPosition() -1 ); - // Guard against hitting delete on group names - // - try { - MessageInfoHolder message = (MessageInfoHolder) mAdapter.getChild(group, item); - switch (keyCode) { - case KeyEvent.KEYCODE_DEL: { onDelete(message); return true;} - case KeyEvent.KEYCODE_C: { onCompose(); return true;} - case KeyEvent.KEYCODE_Q: { onAccounts(); return true; } - case KeyEvent.KEYCODE_F: { onForward(message); return true;} - case KeyEvent.KEYCODE_A: { onReplyAll(message); return true; } - case KeyEvent.KEYCODE_R: { onReply(message); return true; } - } - } - finally { - return super.onKeyDown(keyCode, event); - } - } - - - @Override - public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, - int childPosition, long id) { - FolderInfoHolder folder = (FolderInfoHolder) mAdapter.getGroup(groupPosition); - if (folder.outbox) { - return false; - } - if (childPosition == folder.messages.size() && !folder.loading) { - if (folder.status == null) { - MessagingController.getInstance(getApplication()).loadMoreMessages( - mAccount, - folder.name, - mAdapter.mListener); - return false; - } - else { - MessagingController.getInstance(getApplication()).synchronizeMailbox( - mAccount, - folder.name, - mAdapter.mListener); - return false; - } - } - else if (childPosition >= folder.messages.size()) { - return false; - } - MessageInfoHolder message = (MessageInfoHolder) mAdapter.getChild(groupPosition, childPosition); - - onOpenMessage(folder, message); - - return true; - } - - private void onRefresh(final boolean forceRemote) { - if (forceRemote) { - mRefreshRemote = true; - } - new Thread() { - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - MessagingController.getInstance(getApplication()).listFolders( - mAccount, - forceRemote, - mAdapter.mListener); - if (forceRemote) { - MessagingController.getInstance(getApplication()).sendPendingMessages( - mAccount, - null); - } - } - }.start(); - } - - private void onOpenMessage(FolderInfoHolder folder, MessageInfoHolder message) { - /* - * We set read=true here for UI performance reasons. The actual value will get picked up - * on the refresh when the Activity is resumed but that may take a second or so and we - * don't want this to show and then go away. - * I've gone back and forth on this, and this gives a better UI experience, so I am - * putting it back in. - */ - if (!message.read) { - message.read = true; - mHandler.dataChanged(); - } - - if (folder.name.equals(mAccount.getDraftsFolderName())) { - MessageCompose.actionEditDraft(this, mAccount, message.message); - } - else { - ArrayList folderUids = new ArrayList(); - for (MessageInfoHolder holder : folder.messages) { - folderUids.add(holder.uid); - } - MessageView.actionView(this, mAccount, folder.name, message.uid, folderUids); - } - } - - private void onEditAccount() { - AccountSettings.actionSettings(this, mAccount); - } - - private void onAccounts() { - startActivity(new Intent(this, Accounts.class)); - finish(); - } - - private void onCompose() { - MessageCompose.actionCompose(this, mAccount); - } - - private void onDelete(MessageInfoHolder holder) { - MessagingController.getInstance(getApplication()).deleteMessage( - mAccount, - holder.message.getFolder().getName(), - holder.message, - null); - mAdapter.removeMessage(holder.message.getFolder().getName(), holder.uid); - Toast.makeText(this, R.string.message_deleted_toast, Toast.LENGTH_SHORT).show(); - } - - private void onReply(MessageInfoHolder holder) { - MessageCompose.actionReply(this, mAccount, holder.message, false); - } - - private void onReplyAll(MessageInfoHolder holder) { - MessageCompose.actionReply(this, mAccount, holder.message, true); - } - - private void onForward(MessageInfoHolder holder) { - MessageCompose.actionForward(this, mAccount, holder.message); - } - - private void onToggleRead(MessageInfoHolder holder) { - MessagingController.getInstance(getApplication()).markMessageRead( - mAccount, - holder.message.getFolder().getName(), - holder.uid, - !holder.read); - holder.read = !holder.read; - onRefresh(false); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.refresh: - onRefresh(true); - return true; - case R.id.accounts: - onAccounts(); - return true; - case R.id.compose: - onCompose(); - return true; - case R.id.account_settings: - onEditAccount(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.folder_message_list_option, menu); - return true; - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - ExpandableListContextMenuInfo info = - (ExpandableListContextMenuInfo) item.getMenuInfo(); - int groupPosition = - ExpandableListView.getPackedPositionGroup(info.packedPosition); - int childPosition = - ExpandableListView.getPackedPositionChild(info.packedPosition); - FolderInfoHolder folder = (FolderInfoHolder) mAdapter.getGroup(groupPosition); - if (childPosition < mAdapter.getChildrenCount(groupPosition)) { - MessageInfoHolder holder = - (MessageInfoHolder) mAdapter.getChild(groupPosition, childPosition); - switch (item.getItemId()) { - case R.id.open: - onOpenMessage(folder, holder); - break; - case R.id.delete: - onDelete(holder); - break; - case R.id.reply: - onReply(holder); - break; - case R.id.reply_all: - onReplyAll(holder); - break; - case R.id.forward: - onForward(holder); - break; - case R.id.mark_as_read: - onToggleRead(holder); - break; - } - } - return super.onContextItemSelected(item); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo; - if (ExpandableListView.getPackedPositionType(info.packedPosition) == - ExpandableListView.PACKED_POSITION_TYPE_CHILD) { - long packedPosition = info.packedPosition; - int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition); - int childPosition = ExpandableListView.getPackedPositionChild(packedPosition); - FolderInfoHolder folder = (FolderInfoHolder) mAdapter.getGroup(groupPosition); - if (folder.outbox) { - return; - } - if (childPosition < folder.messages.size()) { - getMenuInflater().inflate(R.menu.folder_message_list_context, menu); - MessageInfoHolder message = - (MessageInfoHolder) mAdapter.getChild(groupPosition, childPosition); - if (message.read) { - menu.findItem(R.id.mark_as_read).setTitle(R.string.mark_as_unread_action); - } - } - } - } - - class FolderMessageListAdapter extends BaseExpandableListAdapter { - private ArrayList mFolders = new ArrayList(); - - private MessagingListener mListener = new MessagingListener() { - @Override - public void listFoldersStarted(Account account) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(true); - } - - @Override - public void listFoldersFailed(Account account, String message) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(false); - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "listFoldersFailed " + message); - } - } - - @Override - public void listFoldersFinished(Account account) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(false); - if (mInitialFolder != null) { - int groupPosition = getFolderPosition(mInitialFolder); - mInitialFolder = null; - if (groupPosition != -1) { - mHandler.expandGroup(groupPosition); - } - } - } - - @Override - public void listFolders(Account account, Folder[] folders) { - if (!account.equals(mAccount)) { - return; - } - for (Folder folder : folders) { - FolderInfoHolder holder = getFolder(folder.getName()); - if (holder == null) { - holder = new FolderInfoHolder(); - mFolders.add(holder); - } - holder.name = folder.getName(); - if (holder.name.equalsIgnoreCase(k9.INBOX)) { - holder.displayName = getString(R.string.special_mailbox_name_inbox); - } - else { - holder.displayName = folder.getName(); - } - if (holder.name.equals(mAccount.getOutboxFolderName())) { - holder.outbox = true; - } - if (holder.messages == null) { - holder.messages = new ArrayList(); - } - try { - folder.open(Folder.OpenMode.READ_WRITE); - holder.unreadMessageCount = folder.getUnreadMessageCount(); - folder.close(false); - } - catch (MessagingException me) { - Log.e(k9.LOG_TAG, "Folder.getUnreadMessageCount() failed", me); - } - } - - Collections.sort(mFolders); - mHandler.dataChanged(); - - - /* - * We will do this eventually. This restores the state of the list in the - * case of a killed Activity but we have some message sync issues to take care of. - */ -// if (mRestoredState != null) { -// if (Config.LOGV) { -// Log.v(k9.LOG_TAG, "Attempting to restore list state"); -// } -// Parcelable listViewState = -// mListView.onRestoreInstanceState(mListViewState); -// mListViewState = null; -// } - - /* - * Now we need to refresh any folders that are currently expanded. We do this - * in case the status or amount of messages has changed. - */ - for (int i = 0, count = getGroupCount(); i < count; i++) { - if (mListView.isGroupExpanded(i)) { - final FolderInfoHolder folder = (FolderInfoHolder) mAdapter.getGroup(i); - new Thread(new FolderUpdateWorker(folder.name, mRefreshRemote)).start(); - } - } - mRefreshRemote = false; - } - - @Override - public void listLocalMessagesStarted(Account account, String folder) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(true); - mHandler.folderLoading(folder, true); - } - - @Override - public void listLocalMessagesFailed(Account account, String folder, String message) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(false); - mHandler.folderLoading(folder, false); - } - - @Override - public void listLocalMessagesFinished(Account account, String folder) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(false); - mHandler.folderLoading(folder, false); - } - - @Override - public void listLocalMessages(Account account, String folder, Message[] messages) { - if (!account.equals(mAccount)) { - return; - } - synchronizeMessages(folder, messages); - } - - @Override - public void synchronizeMailboxStarted( - Account account, - String folder) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(true); - mHandler.folderLoading(folder, true); - mHandler.folderStatus(folder, null); - } - - @Override - public void synchronizeMailboxFinished( - Account account, - String folder, - int totalMessagesInMailbox, - int numNewMessages) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(false); - mHandler.folderLoading(folder, false); - mHandler.folderStatus(folder, null); - onRefresh(false); - } - - @Override - public void synchronizeMailboxFailed( - Account account, - String folder, - String message) { - if (!account.equals(mAccount)) { - return; - } - mHandler.progress(false); - mHandler.folderLoading(folder, false); - mHandler.folderStatus(folder, getString(R.string.status_network_error)); - FolderInfoHolder holder = getFolder(folder); - if (holder != null) { - /* - * Reset the last checked time to 0 so that the next expand will attempt to - * refresh this folder. - */ - holder.lastChecked = 0; - } - } - - @Override - public void synchronizeMailboxNewMessage( - Account account, - String folder, - Message message) { - if (!account.equals(mAccount)) { - return; - } - addOrUpdateMessage(folder, message); - } - - @Override - public void synchronizeMailboxRemovedMessage( - Account account, - String folder, - Message message) { - if (!account.equals(mAccount)) { - return; - } - removeMessage(folder, message.getUid()); - } - - @Override - public void emptyTrashCompleted(Account account) { - if (!account.equals(mAccount)) { - return; - } - onRefresh(false); - } - - @Override - public void sendPendingMessagesCompleted(Account account) { - if (!account.equals(mAccount)) { - return; - } - onRefresh(false); - } - - @Override - public void messageUidChanged( - Account account, - String folder, - String oldUid, - String newUid) { - if (mAccount.equals(account)) { - FolderInfoHolder holder = getFolder(folder); - if (folder != null) { - for (MessageInfoHolder message : holder.messages) { - if (message.uid.equals(oldUid)) { - message.uid = newUid; - message.message.setUid(newUid); - } - } - } - } - } - }; - - private Drawable mAttachmentIcon; - - FolderMessageListAdapter() { - mAttachmentIcon = getResources().getDrawable(R.drawable.ic_mms_attachment_small); - } - - public void removeMessage(String folder, String messageUid) { - FolderInfoHolder f = getFolder(folder); - if (f == null) { - return; - } - MessageInfoHolder m = getMessage(f, messageUid); - if (m == null) { - return; - } - mHandler.removeMessage(f, m); - } - - public void synchronizeMessages(String folder, Message[] messages) { - FolderInfoHolder f = getFolder(folder); - if (f == null) { - return; - } - mHandler.synchronizeMessages(f, messages); - } - - public void addOrUpdateMessage(String folder, Message message) { - addOrUpdateMessage(folder, message, true, true); - } - - private void addOrUpdateMessage(FolderInfoHolder folder, Message message, - boolean sort, boolean notify) { - MessageInfoHolder m = getMessage(folder, message.getUid()); - if (m == null) { - m = new MessageInfoHolder(message, folder); - folder.messages.add(m); - } - else { - m.populate(message, folder); - } - if (sort) { - Collections.sort(folder.messages); - } - if (notify) { - mHandler.dataChanged(); - } - } - - private void addOrUpdateMessage(String folder, Message message, - boolean sort, boolean notify) { - FolderInfoHolder f = getFolder(folder); - if (f == null) { - return; - } - addOrUpdateMessage(f, message, sort, notify); - } - - public MessageInfoHolder getMessage(FolderInfoHolder folder, String messageUid) { - for (MessageInfoHolder message : folder.messages) { - if (message.uid.equals(messageUid)) { - return message; - } - } - return null; - } - - public int getGroupCount() { - return mFolders.size(); - } - - public long getGroupId(int groupPosition) { - return groupPosition; - } - - public Object getGroup(int groupPosition) { - return mFolders.get(groupPosition); - } - - public FolderInfoHolder getFolder(String folder) { - FolderInfoHolder folderHolder = null; - for (int i = 0, count = getGroupCount(); i < count; i++) { - FolderInfoHolder holder = (FolderInfoHolder) getGroup(i); - if (holder.name.equals(folder)) { - folderHolder = holder; - } - } - return folderHolder; - } - - /** - * Gets the group position of the given folder or returns -1 if the folder is not - * found. - * @param folder - * @return - */ - public int getFolderPosition(String folder) { - for (int i = 0, count = getGroupCount(); i < count; i++) { - FolderInfoHolder holder = (FolderInfoHolder) getGroup(i); - if (holder.name.equals(folder)) { - return i; - } - } - return -1; - } - - public View getGroupView(int groupPosition, boolean isExpanded, View convertView, - ViewGroup parent) { - FolderInfoHolder folder = (FolderInfoHolder) getGroup(groupPosition); - View view; - if (convertView != null) { - view = convertView; - } else { - view = mInflater.inflate(R.layout.folder_message_list_group, parent, false); - } - FolderViewHolder holder = (FolderViewHolder) view.getTag(); - if (holder == null) { - holder = new FolderViewHolder(); - holder.folderName = (TextView) view.findViewById(R.id.folder_name); - holder.newMessageCount = (TextView) view.findViewById(R.id.new_message_count); - holder.folderStatus = (TextView) view.findViewById(R.id.folder_status); - view.setTag(holder); - } - holder.folderName.setText(folder.displayName); - - if (folder.status == null) { - holder.folderStatus.setVisibility(View.GONE); - } - else { - holder.folderStatus.setText(folder.status); - holder.folderStatus.setVisibility(View.VISIBLE); - } - - if (folder.unreadMessageCount != 0) { - holder.newMessageCount.setText(Integer.toString(folder.unreadMessageCount)); - holder.newMessageCount.setVisibility(View.VISIBLE); - } - else { - holder.newMessageCount.setVisibility(View.GONE); - } - return view; - } - - public int getChildrenCount(int groupPosition) { - FolderInfoHolder folder = (FolderInfoHolder) getGroup(groupPosition); - return folder.messages.size() + 1; - } - - public long getChildId(int groupPosition, int childPosition) { - FolderInfoHolder folder = (FolderInfoHolder) getGroup(groupPosition); - if (childPosition < folder.messages.size()) { - MessageInfoHolder holder = folder.messages.get(childPosition); - return ((LocalStore.LocalMessage) holder.message).getId(); - } else { - return -1; - } - } - - public Object getChild(int groupPosition, int childPosition) { - FolderInfoHolder folder = (FolderInfoHolder) getGroup(groupPosition); - return folder.messages.get(childPosition); - } - - public View getChildView(int groupPosition, int childPosition, boolean isLastChild, - View convertView, ViewGroup parent) { - FolderInfoHolder folder = (FolderInfoHolder) getGroup(groupPosition); - if (isLastChild) { - View view; - if ((convertView != null) - && (convertView.getId() - == R.layout.folder_message_list_child_footer)) { - view = convertView; - } - else { - view = mInflater.inflate(R.layout.folder_message_list_child_footer, - parent, false); - view.setId(R.layout.folder_message_list_child_footer); - } - FooterViewHolder holder = (FooterViewHolder) view.getTag(); - if (holder == null) { - holder = new FooterViewHolder(); - holder.progress = (ProgressBar) view.findViewById(R.id.progress); - holder.main = (TextView) view.findViewById(R.id.main_text); - view.setTag(holder); - } - if (folder.loading) { - holder.main.setText(getString(R.string.status_loading_more)); - holder.progress.setVisibility(View.VISIBLE); - } - else { - if (folder.status == null) { - holder.main.setText(getString(R.string.message_list_load_more_messages_action)); - } - else { - holder.main.setText(getString(R.string.status_loading_more_failed)); - } - holder.progress.setVisibility(View.GONE); - } - return view; - } - else { - MessageInfoHolder message = - (MessageInfoHolder) getChild(groupPosition, childPosition); - View view; - if ((convertView != null) - && (convertView.getId() != R.layout.folder_message_list_child_footer)) { - view = convertView; - } else { - view = mInflater.inflate(R.layout.folder_message_list_child, parent, false); - } - MessageViewHolder holder = (MessageViewHolder) view.getTag(); - if (holder == null) { - holder = new MessageViewHolder(); - holder.subject = (TextView) view.findViewById(R.id.subject); - holder.from = (TextView) view.findViewById(R.id.from); - holder.date = (TextView) view.findViewById(R.id.date); - holder.chip = view.findViewById(R.id.chip); - /* - * TODO - * The line below and the commented lines a bit further down are work - * in progress for outbox status. They should not be removed. - */ -// holder.status = (TextView) view.findViewById(R.id.status); - - /* - * This will need to move to below if we ever convert this whole thing - * to a combined inbox. - */ - holder.chip.setBackgroundResource(colorChipResId); - - view.setTag(holder); - } - holder.chip.getBackground().setAlpha(message.read ? 0 : 255); - holder.subject.setText(message.subject); - holder.subject.setTypeface(null, message.read ? Typeface.NORMAL : Typeface.BOLD); - holder.from.setText(message.sender); - holder.from.setTypeface(null, message.read ? Typeface.NORMAL : Typeface.BOLD); - holder.date.setText(message.date); - holder.from.setCompoundDrawablesWithIntrinsicBounds(null, null, - message.hasAttachments ? mAttachmentIcon : null, null); -// if (folder.outbox) { -// holder.status.setText("Sending"); -// } -// else { -// holder.status.setText(""); -// } - return view; - } - } - - public boolean hasStableIds() { - return true; - } - - public boolean isChildSelectable(int groupPosition, int childPosition) { - return childPosition < getChildrenCount(groupPosition); - } - - public class FolderInfoHolder implements Comparable { - public String name; - public String displayName; - public ArrayList messages; - public long lastChecked; - public int unreadMessageCount; - public boolean loading; - public String status; - public boolean lastCheckFailed; - - /** - * Outbox is handled differently from any other folder. - */ - public boolean outbox; - - public int compareTo(FolderInfoHolder o) { - String s1 = this.name; - String s2 = o.name; - if (k9.INBOX.equalsIgnoreCase(s1)) { - return -1; - } else if (k9.INBOX.equalsIgnoreCase(s2)) { - return 1; - } else - return s1.toUpperCase().compareTo(s2.toUpperCase()); - } - } - - public class MessageInfoHolder implements Comparable { - public String subject; - public String date; - public Date compareDate; - public String sender; - public boolean hasAttachments; - public String uid; - public boolean read; - public Message message; - - public MessageInfoHolder(Message m, FolderInfoHolder folder) { - populate(m, folder); - } - - public void populate(Message m, FolderInfoHolder folder) { - try { - LocalMessage message = (LocalMessage) m; - Date date = message.getSentDate(); - this.compareDate = date; - if (Utility.isDateToday(date)) { - this.date = mTimeFormat.format(date); - } - else { - this.date = mDateFormat.format(date); - } - this.hasAttachments = message.getAttachmentCount() > 0; - this.read = message.isSet(Flag.SEEN); - if (folder.outbox) { - this.sender = Address.toFriendly( - message.getRecipients(RecipientType.TO)); - } - else { - this.sender = Address.toFriendly(message.getFrom()); - } - this.subject = message.getSubject(); - this.uid = message.getUid(); - this.message = m; - } - catch (MessagingException me) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "Unable to load message info", me); - } - } - } - - public int compareTo(MessageInfoHolder o) { - return this.compareDate.compareTo(o.compareDate) * -1; - } - } - - class FolderViewHolder { - public TextView folderName; - public TextView folderStatus; - public TextView newMessageCount; - } - - class MessageViewHolder { - public TextView subject; - public TextView preview; - public TextView from; - public TextView date; - public View chip; - } - - class FooterViewHolder { - public ProgressBar progress; - public TextView main; - } - } -} diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java deleted file mode 100644 index 5a4cf273a..000000000 --- a/src/com/fsck/k9/activity/MessageCompose.java +++ /dev/null @@ -1,1053 +0,0 @@ - -package com.fsck.k9.activity; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcelable; -import android.provider.OpenableColumns; -import android.text.TextWatcher; -import android.text.util.Rfc822Tokenizer; -import android.util.Config; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.view.View.OnClickListener; -import android.view.View.OnFocusChangeListener; -import android.webkit.WebView; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.MultiAutoCompleteTextView; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.AutoCompleteTextView.Validator; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.EmailAddressAdapter; -import com.fsck.k9.EmailAddressValidator; -import com.fsck.k9.MessagingController; -import com.fsck.k9.MessagingListener; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; -import com.fsck.k9.Utility; -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.Body; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Multipart; -import com.fsck.k9.mail.Part; -import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.internet.MimeBodyPart; -import com.fsck.k9.mail.internet.MimeHeader; -import com.fsck.k9.mail.internet.MimeMessage; -import com.fsck.k9.mail.internet.MimeMultipart; -import com.fsck.k9.mail.internet.MimeUtility; -import com.fsck.k9.mail.internet.TextBody; -import com.fsck.k9.mail.store.LocalStore; -import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBody; - -public class MessageCompose extends Activity implements OnClickListener, OnFocusChangeListener { - private static final String ACTION_REPLY = "com.fsck.k9.intent.action.REPLY"; - private static final String ACTION_REPLY_ALL = "com.fsck.k9.intent.action.REPLY_ALL"; - private static final String ACTION_FORWARD = "com.fsck.k9.intent.action.FORWARD"; - private static final String ACTION_EDIT_DRAFT = "com.fsck.k9.intent.action.EDIT_DRAFT"; - - private static final String EXTRA_ACCOUNT = "account"; - private static final String EXTRA_FOLDER = "folder"; - private static final String EXTRA_MESSAGE = "message"; - - private static final String STATE_KEY_ATTACHMENTS = - "com.fsck.k9.activity.MessageCompose.attachments"; - private static final String STATE_KEY_CC_SHOWN = - "com.fsck.k9.activity.MessageCompose.ccShown"; - private static final String STATE_KEY_BCC_SHOWN = - "com.fsck.k9.activity.MessageCompose.bccShown"; - private static final String STATE_KEY_QUOTED_TEXT_SHOWN = - "com.fsck.k9.activity.MessageCompose.quotedTextShown"; - private static final String STATE_KEY_SOURCE_MESSAGE_PROCED = - "com.fsck.k9.activity.MessageCompose.stateKeySourceMessageProced"; - private static final String STATE_KEY_DRAFT_UID = - "com.fsck.k9.activity.MessageCompose.draftUid"; - - private static final int MSG_PROGRESS_ON = 1; - private static final int MSG_PROGRESS_OFF = 2; - private static final int MSG_UPDATE_TITLE = 3; - private static final int MSG_SKIPPED_ATTACHMENTS = 4; - private static final int MSG_SAVED_DRAFT = 5; - private static final int MSG_DISCARDED_DRAFT = 6; - - private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1; - - private Account mAccount; - private String mFolder; - private String mSourceMessageUid; - private Message mSourceMessage; - /** - * Indicates that the source message has been processed at least once and should not - * be processed on any subsequent loads. This protects us from adding attachments that - * have already been added from the restore of the view state. - */ - private boolean mSourceMessageProcessed = false; - - private MultiAutoCompleteTextView mToView; - private MultiAutoCompleteTextView mCcView; - private MultiAutoCompleteTextView mBccView; - private EditText mSubjectView; - private EditText mMessageContentView; - private Button mSendButton; - private Button mDiscardButton; - private Button mSaveButton; - private LinearLayout mAttachments; - private View mQuotedTextBar; - private ImageButton mQuotedTextDelete; - private WebView mQuotedText; - - private boolean mDraftNeedsSaving = false; - - /** - * The draft uid of this message. This is used when saving drafts so that the same draft is - * overwritten instead of being created anew. This property is null until the first save. - */ - private String mDraftUid; - - private Handler mHandler = new Handler() { - @Override - public void handleMessage(android.os.Message msg) { - switch (msg.what) { - case MSG_PROGRESS_ON: - setProgressBarIndeterminateVisibility(true); - break; - case MSG_PROGRESS_OFF: - setProgressBarIndeterminateVisibility(false); - break; - case MSG_UPDATE_TITLE: - updateTitle(); - break; - case MSG_SKIPPED_ATTACHMENTS: - Toast.makeText( - MessageCompose.this, - getString(R.string.message_compose_attachments_skipped_toast), - Toast.LENGTH_LONG).show(); - break; - case MSG_SAVED_DRAFT: - Toast.makeText( - MessageCompose.this, - getString(R.string.message_saved_toast), - Toast.LENGTH_LONG).show(); - break; - case MSG_DISCARDED_DRAFT: - Toast.makeText( - MessageCompose.this, - getString(R.string.message_discarded_toast), - Toast.LENGTH_LONG).show(); - break; - default: - super.handleMessage(msg); - break; - } - } - }; - - private Listener mListener = new Listener(); - private EmailAddressAdapter mAddressAdapter; - private Validator mAddressValidator; - - - class Attachment implements Serializable { - public String name; - public String contentType; - public long size; - public Uri uri; - } - - /** - * Compose a new message using the given account. If account is null the default account - * will be used. - * @param context - * @param account - */ - public static void actionCompose(Context context, Account account) { - Intent i = new Intent(context, MessageCompose.class); - i.putExtra(EXTRA_ACCOUNT, account); - context.startActivity(i); - } - - /** - * Compose a new message as a reply to the given message. If replyAll is true the function - * is reply all instead of simply reply. - * @param context - * @param account - * @param message - * @param replyAll - */ - public static void actionReply( - Context context, - Account account, - Message message, - boolean replyAll) { - Intent i = new Intent(context, MessageCompose.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_FOLDER, message.getFolder().getName()); - i.putExtra(EXTRA_MESSAGE, message.getUid()); - if (replyAll) { - i.setAction(ACTION_REPLY_ALL); - } - else { - i.setAction(ACTION_REPLY); - } - context.startActivity(i); - } - - /** - * Compose a new message as a forward of the given message. - * @param context - * @param account - * @param message - */ - public static void actionForward(Context context, Account account, Message message) { - Intent i = new Intent(context, MessageCompose.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_FOLDER, message.getFolder().getName()); - i.putExtra(EXTRA_MESSAGE, message.getUid()); - i.setAction(ACTION_FORWARD); - context.startActivity(i); - } - - /** - * Continue composition of the given message. This action modifies the way this Activity - * handles certain actions. - * Save will attempt to replace the message in the given folder with the updated version. - * Discard will delete the message from the given folder. - * @param context - * @param account - * @param folder - * @param message - */ - public static void actionEditDraft(Context context, Account account, Message message) { - Intent i = new Intent(context, MessageCompose.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_FOLDER, message.getFolder().getName()); - i.putExtra(EXTRA_MESSAGE, message.getUid()); - i.setAction(ACTION_EDIT_DRAFT); - context.startActivity(i); - } - - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - - setContentView(R.layout.message_compose); - - mAddressAdapter = new EmailAddressAdapter(this); - mAddressValidator = new EmailAddressValidator(); - - mToView = (MultiAutoCompleteTextView)findViewById(R.id.to); - mCcView = (MultiAutoCompleteTextView)findViewById(R.id.cc); - mBccView = (MultiAutoCompleteTextView)findViewById(R.id.bcc); - mSubjectView = (EditText)findViewById(R.id.subject); - mMessageContentView = (EditText)findViewById(R.id.message_content); - mAttachments = (LinearLayout)findViewById(R.id.attachments); - mQuotedTextBar = findViewById(R.id.quoted_text_bar); - mQuotedTextDelete = (ImageButton)findViewById(R.id.quoted_text_delete); - mQuotedText = (WebView)findViewById(R.id.quoted_text); - - TextWatcher watcher = new TextWatcher() { - public void beforeTextChanged(CharSequence s, int start, - int before, int after) { } - - public void onTextChanged(CharSequence s, int start, - int before, int count) { - mDraftNeedsSaving = true; - } - - public void afterTextChanged(android.text.Editable s) { } - }; - - mToView.addTextChangedListener(watcher); - mCcView.addTextChangedListener(watcher); - mBccView.addTextChangedListener(watcher); - mSubjectView.addTextChangedListener(watcher); - mMessageContentView.addTextChangedListener(watcher); - - /* - * We set this to invisible by default. Other methods will turn it back on if it's - * needed. - */ - mQuotedTextBar.setVisibility(View.GONE); - mQuotedText.setVisibility(View.GONE); - - mQuotedTextDelete.setOnClickListener(this); - - mToView.setAdapter(mAddressAdapter); - mToView.setTokenizer(new Rfc822Tokenizer()); - mToView.setValidator(mAddressValidator); - - mCcView.setAdapter(mAddressAdapter); - mCcView.setTokenizer(new Rfc822Tokenizer()); - mCcView.setValidator(mAddressValidator); - - mBccView.setAdapter(mAddressAdapter); - mBccView.setTokenizer(new Rfc822Tokenizer()); - mBccView.setValidator(mAddressValidator); - - - mSubjectView.setOnFocusChangeListener(this); - - if (savedInstanceState != null) { - /* - * This data gets used in onCreate, so grab it here instead of onRestoreIntstanceState - */ - mSourceMessageProcessed = - savedInstanceState.getBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, false); - } - - Intent intent = getIntent(); - - String action = intent.getAction(); - - if (Intent.ACTION_VIEW.equals(action) || Intent.ACTION_SENDTO.equals(action)) { - /* - * Someone has clicked a mailto: link. The address is in the URI. - */ - mAccount = Preferences.getPreferences(this).getDefaultAccount(); - if (mAccount == null) { - /* - * There are no accounts set up. This should not have happened. Prompt the - * user to set up an account as an acceptable bailout. - */ - startActivity(new Intent(this, Accounts.class)); - mDraftNeedsSaving = false; - finish(); - return; - } - if (intent.getData() != null) { - Uri uri = intent.getData(); - try { - if (uri.getScheme().equalsIgnoreCase("mailto")) { - Address[] addresses = Address.parse(uri.getSchemeSpecificPart()); - addAddresses(mToView, addresses); - } - } - catch (Exception e) { - /* - * If we can't extract any information from the URI it's okay. They can - * still compose a message. - */ - } - } - } - else if (Intent.ACTION_SEND.equals(action)) { - /* - * Someone is trying to compose an email with an attachment, probably Pictures. - * The Intent should contain an EXTRA_STREAM with the data to attach. - */ - - mAccount = Preferences.getPreferences(this).getDefaultAccount(); - if (mAccount == null) { - /* - * There are no accounts set up. This should not have happened. Prompt the - * user to set up an account as an acceptable bailout. - */ - startActivity(new Intent(this, Accounts.class)); - mDraftNeedsSaving = false; - finish(); - return; - } - - String type = intent.getType(); - Uri stream = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); - if (stream != null && type != null) { - if (MimeUtility.mimeTypeMatches(type, k9.ACCEPTABLE_ATTACHMENT_SEND_TYPES)) { - addAttachment(stream); - } - } - } - else { - mAccount = (Account) intent.getSerializableExtra(EXTRA_ACCOUNT); - mFolder = (String) intent.getStringExtra(EXTRA_FOLDER); - mSourceMessageUid = (String) intent.getStringExtra(EXTRA_MESSAGE); - } - - if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action) || - ACTION_FORWARD.equals(action) || ACTION_EDIT_DRAFT.equals(action)) { - /* - * If we need to load the message we add ourself as a message listener here - * so we can kick it off. Normally we add in onResume but we don't - * want to reload the message every time the activity is resumed. - * There is no harm in adding twice. - */ - MessagingController.getInstance(getApplication()).addListener(mListener); - MessagingController.getInstance(getApplication()).loadMessageForView( - mAccount, - mFolder, - mSourceMessageUid, - mListener); - } - - addAddress(mBccView, new Address(mAccount.getAlwaysBcc(), "")); - updateTitle(); - } - - public void onResume() { - super.onResume(); - MessagingController.getInstance(getApplication()).addListener(mListener); - } - - public void onPause() { - super.onPause(); - saveIfNeeded(); - MessagingController.getInstance(getApplication()).removeListener(mListener); - } - - /** - * The framework handles most of the fields, but we need to handle stuff that we - * dynamically show and hide: - * Attachment list, - * Cc field, - * Bcc field, - * Quoted text, - */ - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - saveIfNeeded(); - ArrayList attachments = new ArrayList(); - for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) { - View view = mAttachments.getChildAt(i); - Attachment attachment = (Attachment) view.getTag(); - attachments.add(attachment.uri); - } - outState.putParcelableArrayList(STATE_KEY_ATTACHMENTS, attachments); - outState.putBoolean(STATE_KEY_CC_SHOWN, mCcView.getVisibility() == View.VISIBLE); - outState.putBoolean(STATE_KEY_BCC_SHOWN, mBccView.getVisibility() == View.VISIBLE); - outState.putBoolean(STATE_KEY_QUOTED_TEXT_SHOWN, - mQuotedTextBar.getVisibility() == View.VISIBLE); - outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, mSourceMessageProcessed); - outState.putString(STATE_KEY_DRAFT_UID, mDraftUid); - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - ArrayList attachments = (ArrayList) - savedInstanceState.getParcelableArrayList(STATE_KEY_ATTACHMENTS); - mAttachments.removeAllViews(); - for (Parcelable p : attachments) { - Uri uri = (Uri) p; - addAttachment(uri); - } - - mCcView.setVisibility(savedInstanceState.getBoolean(STATE_KEY_CC_SHOWN) ? - View.VISIBLE : View.GONE); - mBccView.setVisibility(savedInstanceState.getBoolean(STATE_KEY_BCC_SHOWN) ? - View.VISIBLE : View.GONE); - mQuotedTextBar.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? - View.VISIBLE : View.GONE); - mQuotedText.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? - View.VISIBLE : View.GONE); - mDraftUid = savedInstanceState.getString(STATE_KEY_DRAFT_UID); - mDraftNeedsSaving = false; - } - - private void updateTitle() { - if (mSubjectView.getText().length() == 0) { - setTitle(R.string.compose_title); - } else { - setTitle(mSubjectView.getText().toString()); - } - } - - public void onFocusChange(View view, boolean focused) { - if (!focused) { - updateTitle(); - } - } - - private void addAddresses(MultiAutoCompleteTextView view, Address[] addresses) { - if (addresses == null) { - return; - } - for (Address address : addresses) { - addAddress(view, address); - } - } - - private void addAddress(MultiAutoCompleteTextView view, Address address) { - view.append(address + ", "); - } - - private Address[] getAddresses(MultiAutoCompleteTextView view) { - Address[] addresses = Address.parse(view.getText().toString().trim()); - return addresses; - } - - private MimeMessage createMessage() throws MessagingException { - MimeMessage message = new MimeMessage(); - message.setSentDate(new Date()); - Address from = new Address(mAccount.getEmail(), mAccount.getName()); - message.setFrom(from); - message.setRecipients(RecipientType.TO, getAddresses(mToView)); - message.setRecipients(RecipientType.CC, getAddresses(mCcView)); - message.setRecipients(RecipientType.BCC, getAddresses(mBccView)); - message.setSubject(mSubjectView.getText().toString()); - // XXX TODO - not sure why this won't add header - // message.setHeader("X-User-Agent", getString(R.string.message_header_mua)); - - - - /* - * Build the Body that will contain the text of the message. We'll decide where to - * include it later. - */ - - String text = mMessageContentView.getText().toString(); - - if (mQuotedTextBar.getVisibility() == View.VISIBLE) { - String action = getIntent().getAction(); - String quotedText = null; - Part part = MimeUtility.findFirstPartByMimeType(mSourceMessage, - "text/plain"); - if (part != null) { - quotedText = MimeUtility.getTextFromPart(part); - } - if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) { - text += String.format( - getString(R.string.message_compose_reply_header_fmt), - Address.toString(mSourceMessage.getFrom())); - if (quotedText != null) { - text += quotedText.replaceAll("(?m)^", ">"); - } - } - else if (ACTION_FORWARD.equals(action)) { - text += String.format( - getString(R.string.message_compose_fwd_header_fmt), - mSourceMessage.getSubject(), - Address.toString(mSourceMessage.getFrom()), - Address.toString( - mSourceMessage.getRecipients(RecipientType.TO)), - Address.toString( - mSourceMessage.getRecipients(RecipientType.CC))); - if (quotedText != null) { - text += quotedText; - } - } - } - - - - text = appendSignature(text); - - - TextBody body = new TextBody(text); - - if (mAttachments.getChildCount() > 0) { - /* - * The message has attachments that need to be included. First we add the part - * containing the text that will be sent and then we include each attachment. - */ - - MimeMultipart mp; - - mp = new MimeMultipart(); - mp.addBodyPart(new MimeBodyPart(body, "text/plain")); - - for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) { - Attachment attachment = (Attachment) mAttachments.getChildAt(i).getTag(); - MimeBodyPart bp = new MimeBodyPart( - new LocalStore.LocalAttachmentBody(attachment.uri, getApplication())); - bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n name=\"%s\"", - attachment.contentType, - attachment.name)); - bp.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); - bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, - String.format("attachment;\n filename=\"%s\"", - attachment.name)); - mp.addBodyPart(bp); - } - - message.setBody(mp); - } - else { - /* - * No attachments to include, just stick the text body in the message and call - * it good. - */ - message.setBody(body); - } - - return message; - } - - private String appendSignature (String text) { - String mSignature; - mSignature = mAccount.getSignature(); - - if (mSignature != null && ! mSignature.contentEquals("")){ - text += "\n-- \n" + mAccount.getSignature(); - } - - return text; - } - - - private void sendOrSaveMessage(boolean save) { - /* - * Create the message from all the data the user has entered. - */ - MimeMessage message; - try { - message = createMessage(); - } - catch (MessagingException me) { - Log.e(k9.LOG_TAG, "Failed to create new message for send or save.", me); - throw new RuntimeException("Failed to create a new message for send or save.", me); - } - - if (save) { - /* - * Save a draft - */ - if (mDraftUid != null) { - message.setUid(mDraftUid); - } - else if (ACTION_EDIT_DRAFT.equals(getIntent().getAction())) { - /* - * We're saving a previously saved draft, so update the new message's uid - * to the old message's uid. - */ - message.setUid(mSourceMessageUid); - } - MessagingController.getInstance(getApplication()).saveDraft(mAccount, message); - mDraftUid = message.getUid(); - - // Don't display the toast if the user is just changing the orientation - if ((getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { - mHandler.sendEmptyMessage(MSG_SAVED_DRAFT); - } - } - else { - /* - * Send the message - * TODO Is it possible for us to be editing a draft with a null source message? Don't - * think so. Could probably remove below check. - */ - if (ACTION_EDIT_DRAFT.equals(getIntent().getAction()) - && mSourceMessageUid != null) { - /* - * We're sending a previously saved draft, so delete the old draft first. - */ - MessagingController.getInstance(getApplication()).deleteMessage( - mAccount, - mFolder, - mSourceMessage, - null); - } - MessagingController.getInstance(getApplication()).sendMessage(mAccount, message, null); - } - } - - private void saveIfNeeded() { - if (!mDraftNeedsSaving) { - return; - } - mDraftNeedsSaving = false; - sendOrSaveMessage(true); - } - - private void onSend() { - if (getAddresses(mToView).length == 0 && - getAddresses(mCcView).length == 0 && - getAddresses(mBccView).length == 0) { - mToView.setError(getString(R.string.message_compose_error_no_recipients)); - Toast.makeText(this, getString(R.string.message_compose_error_no_recipients), - Toast.LENGTH_LONG).show(); - return; - } - sendOrSaveMessage(false); - mDraftNeedsSaving = false; - finish(); - } - - private void onDiscard() { - if (mSourceMessageUid != null) { - if (ACTION_EDIT_DRAFT.equals(getIntent().getAction()) && mSourceMessageUid != null) { - MessagingController.getInstance(getApplication()).deleteMessage( - mAccount, - mFolder, - mSourceMessage, - null); - } - } - mHandler.sendEmptyMessage(MSG_DISCARDED_DRAFT); - mDraftNeedsSaving = false; - finish(); - } - - private void onSave() { - saveIfNeeded(); - finish(); - } - - private void onAddCcBcc() { - mCcView.setVisibility(View.VISIBLE); - mBccView.setVisibility(View.VISIBLE); - } - - /** - * Kick off a picker for whatever kind of MIME types we'll accept and let Android take over. - */ - private void onAddAttachment() { - Intent i = new Intent(Intent.ACTION_GET_CONTENT); - i.addCategory(Intent.CATEGORY_OPENABLE); - i.setType(k9.ACCEPTABLE_ATTACHMENT_SEND_TYPES[0]); - startActivityForResult(Intent.createChooser(i, null), ACTIVITY_REQUEST_PICK_ATTACHMENT); - } - - private void addAttachment(Uri uri) { - addAttachment(uri, -1, null); - } - - private void addAttachment(Uri uri, int size, String name) { - ContentResolver contentResolver = getContentResolver(); - - String contentType = contentResolver.getType(uri); - - if (contentType == null) { - contentType = ""; - } - - Attachment attachment = new Attachment(); - attachment.name = name; - attachment.contentType = contentType; - attachment.size = size; - attachment.uri = uri; - - if (attachment.size == -1 || attachment.name == null) { - Cursor metadataCursor = contentResolver.query( - uri, - new String[]{ OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE }, - null, - null, - null); - if (metadataCursor != null) { - try { - if (metadataCursor.moveToFirst()) { - if (attachment.name == null) { - attachment.name = metadataCursor.getString(0); - } - if (attachment.size == -1) { - attachment.size = metadataCursor.getInt(1); - } - } - } finally { - metadataCursor.close(); - } - } - } - - if (attachment.name == null) { - attachment.name = uri.getLastPathSegment(); - } - - View view = getLayoutInflater().inflate( - R.layout.message_compose_attachment, - mAttachments, - false); - TextView nameView = (TextView)view.findViewById(R.id.attachment_name); - ImageButton delete = (ImageButton)view.findViewById(R.id.attachment_delete); - nameView.setText(attachment.name); - delete.setOnClickListener(this); - delete.setTag(view); - view.setTag(attachment); - mAttachments.addView(view); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (data == null) { - return; - } - addAttachment(data.getData()); - mDraftNeedsSaving = true; - } - - public void onClick(View view) { - switch (view.getId()) { - case R.id.attachment_delete: - /* - * The view is the delete button, and we have previously set the tag of - * the delete button to the view that owns it. We don't use parent because the - * view is very complex and could change in the future. - */ - mAttachments.removeView((View) view.getTag()); - mDraftNeedsSaving = true; - break; - case R.id.quoted_text_delete: - mQuotedTextBar.setVisibility(View.GONE); - mQuotedText.setVisibility(View.GONE); - mDraftNeedsSaving = true; - break; - } - } - - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.send: - onSend(); - break; - case R.id.save: - onSave(); - break; - case R.id.discard: - onDiscard(); - break; - case R.id.add_cc_bcc: - onAddCcBcc(); - break; - case R.id.add_attachment: - onAddAttachment(); - break; - default: - return super.onOptionsItemSelected(item); - } - return true; - } - - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.message_compose_option, menu); - return true; - } - - /** - * Returns true if all attachments were able to be attached, otherwise returns false. - */ - private boolean loadAttachments(Part part, int depth) throws MessagingException { - if (part.getBody() instanceof Multipart) { - Multipart mp = (Multipart) part.getBody(); - boolean ret = true; - for (int i = 0, count = mp.getCount(); i < count; i++) { - if (!loadAttachments(mp.getBodyPart(i), depth + 1)) { - ret = false; - } - } - return ret; - } else { - String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); - String name = MimeUtility.getHeaderParameter(contentType, "name"); - if (name != null) { - Body body = part.getBody(); - if (body != null && body instanceof LocalAttachmentBody) { - final Uri uri = ((LocalAttachmentBody) body).getContentUri(); - mHandler.post(new Runnable() { - public void run() { - addAttachment(uri); - } - }); - } - else { - return false; - } - } - return true; - } - } - - /** - * Pull out the parts of the now loaded source message and apply them to the new message - * depending on the type of message being composed. - * @param message - */ - private void processSourceMessage(Message message) { - String action = getIntent().getAction(); - if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) { - try { - if (message.getSubject() != null && - !message.getSubject().toLowerCase().startsWith("re:")) { - mSubjectView.setText("Re: " + message.getSubject()); - } - else { - mSubjectView.setText(message.getSubject()); - } - /* - * If a reply-to was included with the message use that, otherwise use the from - * or sender address. - */ - Address[] replyToAddresses; - if (message.getReplyTo().length > 0) { - addAddresses(mToView, replyToAddresses = message.getReplyTo()); - } - else { - addAddresses(mToView, replyToAddresses = message.getFrom()); - } - if (ACTION_REPLY_ALL.equals(action)) { - for (Address address : message.getRecipients(RecipientType.TO)) { - if (!address.getAddress().equalsIgnoreCase(mAccount.getEmail())) { - addAddress(mToView, address); - } - } - if (message.getRecipients(RecipientType.CC).length > 0) { - for (Address address : message.getRecipients(RecipientType.CC)) { - if (!Utility.arrayContains(replyToAddresses, address)) { - addAddress(mCcView, address); - } - } - mCcView.setVisibility(View.VISIBLE); - } - } - - Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain"); - if (part == null) { - part = MimeUtility.findFirstPartByMimeType(message, "text/html"); - } - if (part != null) { - String text = MimeUtility.getTextFromPart(part); - if (text != null) { - mQuotedTextBar.setVisibility(View.VISIBLE); - mQuotedText.setVisibility(View.VISIBLE); - mQuotedText.loadDataWithBaseURL("email://", text, part.getMimeType(), - "utf-8", null); - } - } - } - catch (MessagingException me) { - /* - * This really should not happen at this point but if it does it's okay. - * The user can continue composing their message. - */ - } - } - else if (ACTION_FORWARD.equals(action)) { - try { - if (message.getSubject() != null && - !message.getSubject().toLowerCase().startsWith("fwd:")) { - mSubjectView.setText("Fwd: " + message.getSubject()); - } - else { - mSubjectView.setText(message.getSubject()); - } - - Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain"); - if (part == null) { - part = MimeUtility.findFirstPartByMimeType(message, "text/html"); - } - if (part != null) { - String text = MimeUtility.getTextFromPart(part); - if (text != null) { - mQuotedTextBar.setVisibility(View.VISIBLE); - mQuotedText.setVisibility(View.VISIBLE); - mQuotedText.loadDataWithBaseURL("email://", text, part.getMimeType(), - "utf-8", null); - } - } - if (!mSourceMessageProcessed) { - if (!loadAttachments(message, 0)) { - mHandler.sendEmptyMessage(MSG_SKIPPED_ATTACHMENTS); - } - } - } - catch (MessagingException me) { - /* - * This really should not happen at this point but if it does it's okay. - * The user can continue composing their message. - */ - } - } - else if (ACTION_EDIT_DRAFT.equals(action)) { - try { - mSubjectView.setText(message.getSubject()); - addAddresses(mToView, message.getRecipients(RecipientType.TO)); - if (message.getRecipients(RecipientType.CC).length > 0) { - addAddresses(mCcView, message.getRecipients(RecipientType.CC)); - mCcView.setVisibility(View.VISIBLE); - } - if (message.getRecipients(RecipientType.BCC).length > 0) { - addAddresses(mBccView, message.getRecipients(RecipientType.BCC)); - mBccView.setVisibility(View.VISIBLE); - } - Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain"); - if (part != null) { - String text = MimeUtility.getTextFromPart(part); - mMessageContentView.setText(text); - } - if (!mSourceMessageProcessed) { - loadAttachments(message, 0); - } - } - catch (MessagingException me) { - // TODO - } - } - mSourceMessageProcessed = true; - mDraftNeedsSaving = false; - } - - class Listener extends MessagingListener { - @Override - public void loadMessageForViewStarted(Account account, String folder, String uid) { - mHandler.sendEmptyMessage(MSG_PROGRESS_ON); - } - - @Override - public void loadMessageForViewFinished(Account account, String folder, String uid, - Message message) { - mHandler.sendEmptyMessage(MSG_PROGRESS_OFF); - } - - @Override - public void loadMessageForViewBodyAvailable(Account account, String folder, String uid, - final Message message) { - mSourceMessage = message; - runOnUiThread(new Runnable() { - public void run() { - processSourceMessage(message); - } - }); - } - - @Override - public void loadMessageForViewFailed(Account account, String folder, String uid, - final String message) { - mHandler.sendEmptyMessage(MSG_PROGRESS_OFF); - // TODO show network error - } - - @Override - public void messageUidChanged( - Account account, - String folder, - String oldUid, - String newUid) { - if (account.equals(mAccount) - && (folder.equals(mFolder) - || (mFolder == null - && folder.equals(mAccount.getDraftsFolderName())))) { - if (oldUid.equals(mDraftUid)) { - mDraftUid = newUid; - } - if (oldUid.equals(mSourceMessageUid)) { - mSourceMessageUid = newUid; - } - if (mSourceMessage != null && (oldUid.equals(mSourceMessage.getUid()))) { - mSourceMessage.setUid(newUid); - } - } - } - } -} diff --git a/src/com/fsck/k9/activity/MessageView.java b/src/com/fsck/k9/activity/MessageView.java deleted file mode 100644 index 532096648..000000000 --- a/src/com/fsck/k9/activity/MessageView.java +++ /dev/null @@ -1,891 +0,0 @@ - -package com.fsck.k9.activity; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Map; -import java.util.regex.Matcher; - -import org.apache.commons.io.IOUtils; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.MediaScannerConnection; -import android.media.MediaScannerConnection.MediaScannerConnectionClient; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.os.Handler; -import android.os.Process; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.util.Regex; -import android.text.util.Linkify; -import android.util.Config; -import android.util.Log; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.view.View.OnClickListener; -import android.webkit.CacheManager; -import android.webkit.UrlInterceptHandler; -import android.webkit.WebView; -import android.webkit.CacheManager.CacheResult; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.MessagingController; -import com.fsck.k9.MessagingListener; -import com.fsck.k9.R; -import com.fsck.k9.Utility; -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Multipart; -import com.fsck.k9.mail.Part; -import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.internet.MimeHeader; -import com.fsck.k9.mail.internet.MimeUtility; -import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBody; -import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBodyPart; -import com.fsck.k9.mail.store.LocalStore.LocalMessage; -import com.fsck.k9.provider.AttachmentProvider; - -public class MessageView extends Activity - implements UrlInterceptHandler, OnClickListener { - private static final String EXTRA_ACCOUNT = "com.fsck.k9.MessageView_account"; - private static final String EXTRA_FOLDER = "com.fsck.k9.MessageView_folder"; - private static final String EXTRA_MESSAGE = "com.fsck.k9.MessageView_message"; - private static final String EXTRA_FOLDER_UIDS = "com.fsck.k9.MessageView_folderUids"; - private static final String EXTRA_NEXT = "com.fsck.k9.MessageView_next"; - - private TextView mFromView; - private TextView mDateView; - private TextView mToView; - private TextView mSubjectView; - private WebView mMessageContentView; - private LinearLayout mAttachments; - private View mAttachmentIcon; - private View mShowPicturesSection; - - private Account mAccount; - private String mFolder; - private String mMessageUid; - private ArrayList mFolderUids; - - private Message mMessage; - private String mNextMessageUid = null; - private String mPreviousMessageUid = null; - - private DateFormat mDateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); - private DateFormat mTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT); - - private Listener mListener = new Listener(); - private MessageViewHandler mHandler = new MessageViewHandler(); - - - - - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_DEL: { onDelete(); return true;} - case KeyEvent.KEYCODE_F: { onForward(); return true;} - case KeyEvent.KEYCODE_A: { onReplyAll(); return true; } - case KeyEvent.KEYCODE_R: { onReply(); return true; } - case KeyEvent.KEYCODE_J: { onPrevious(); return true; } - case KeyEvent.KEYCODE_K: { onNext(); return true; } - } - return super.onKeyDown(keyCode, event); - } - - - - class MessageViewHandler extends Handler { - private static final int MSG_PROGRESS = 2; - private static final int MSG_ADD_ATTACHMENT = 3; - private static final int MSG_SET_ATTACHMENTS_ENABLED = 4; - private static final int MSG_SET_HEADERS = 5; - private static final int MSG_NETWORK_ERROR = 6; - private static final int MSG_ATTACHMENT_SAVED = 7; - private static final int MSG_ATTACHMENT_NOT_SAVED = 8; - private static final int MSG_SHOW_SHOW_PICTURES = 9; - private static final int MSG_FETCHING_ATTACHMENT = 10; - - @Override - public void handleMessage(android.os.Message msg) { - switch (msg.what) { - case MSG_PROGRESS: - setProgressBarIndeterminateVisibility(msg.arg1 != 0); - break; - case MSG_ADD_ATTACHMENT: - mAttachments.addView((View) msg.obj); - mAttachments.setVisibility(View.VISIBLE); - break; - case MSG_SET_ATTACHMENTS_ENABLED: - for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) { - Attachment attachment = (Attachment) mAttachments.getChildAt(i).getTag(); - attachment.viewButton.setEnabled(msg.arg1 == 1); - attachment.downloadButton.setEnabled(msg.arg1 == 1); - } - break; - case MSG_SET_HEADERS: - String[] values = (String[]) msg.obj; - setTitle(values[0]); - mSubjectView.setText(values[0]); - mFromView.setText(values[1]); - mDateView.setText(values[2]); - mToView.setText(values[3]); - mAttachmentIcon.setVisibility(msg.arg1 == 1 ? View.VISIBLE : View.GONE); - break; - case MSG_NETWORK_ERROR: - Toast.makeText(MessageView.this, - R.string.status_network_error, Toast.LENGTH_LONG).show(); - break; - case MSG_ATTACHMENT_SAVED: - Toast.makeText(MessageView.this, String.format( - getString(R.string.message_view_status_attachment_saved), msg.obj), - Toast.LENGTH_LONG).show(); - break; - case MSG_ATTACHMENT_NOT_SAVED: - Toast.makeText(MessageView.this, - getString(R.string.message_view_status_attachment_not_saved), - Toast.LENGTH_LONG).show(); - break; - case MSG_SHOW_SHOW_PICTURES: - mShowPicturesSection.setVisibility(msg.arg1 == 1 ? View.VISIBLE : View.GONE); - break; - case MSG_FETCHING_ATTACHMENT: - Toast.makeText(MessageView.this, - getString(R.string.message_view_fetching_attachment_toast), - Toast.LENGTH_SHORT).show(); - break; - default: - super.handleMessage(msg); - } - } - - public void progress(boolean progress) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_PROGRESS; - msg.arg1 = progress ? 1 : 0; - sendMessage(msg); - } - - public void addAttachment(View attachmentView) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_ADD_ATTACHMENT; - msg.obj = attachmentView; - sendMessage(msg); - } - - public void setAttachmentsEnabled(boolean enabled) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_SET_ATTACHMENTS_ENABLED; - msg.arg1 = enabled ? 1 : 0; - sendMessage(msg); - } - - public void setHeaders( - String subject, - String from, - String date, - String to, - boolean hasAttachments) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_SET_HEADERS; - msg.arg1 = hasAttachments ? 1 : 0; - msg.obj = new String[] { subject, from, date, to }; - sendMessage(msg); - } - - public void networkError() { - sendEmptyMessage(MSG_NETWORK_ERROR); - } - - public void attachmentSaved(String filename) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_ATTACHMENT_SAVED; - msg.obj = filename; - sendMessage(msg); - } - - public void attachmentNotSaved() { - sendEmptyMessage(MSG_ATTACHMENT_NOT_SAVED); - } - - public void fetchingAttachment() { - sendEmptyMessage(MSG_FETCHING_ATTACHMENT); - } - - public void showShowPictures(boolean show) { - android.os.Message msg = new android.os.Message(); - msg.what = MSG_SHOW_SHOW_PICTURES; - msg.arg1 = show ? 1 : 0; - sendMessage(msg); - } - - - - } - - class Attachment { - public String name; - public String contentType; - public long size; - public LocalAttachmentBodyPart part; - public Button viewButton; - public Button downloadButton; - public ImageView iconView; - } - - public static void actionView(Context context, Account account, - String folder, String messageUid, ArrayList folderUids) { - actionView(context, account, folder, messageUid, folderUids, null); - } - - public static void actionView(Context context, Account account, - String folder, String messageUid, ArrayList folderUids, Bundle extras) { - Intent i = new Intent(context, MessageView.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_FOLDER, folder); - i.putExtra(EXTRA_MESSAGE, messageUid); - i.putExtra(EXTRA_FOLDER_UIDS, folderUids); - if (extras != null) { - i.putExtras(extras); - } - context.startActivity(i); - } - - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - - setContentView(R.layout.message_view); - - mFromView = (TextView)findViewById(R.id.from); - mToView = (TextView)findViewById(R.id.to); - mSubjectView = (TextView)findViewById(R.id.subject); - mDateView = (TextView)findViewById(R.id.date); - mMessageContentView = (WebView)findViewById(R.id.message_content); - mAttachments = (LinearLayout)findViewById(R.id.attachments); - mAttachmentIcon = findViewById(R.id.attachment); - mShowPicturesSection = findViewById(R.id.show_pictures_section); - - mMessageContentView.setVerticalScrollBarEnabled(false); - mAttachments.setVisibility(View.GONE); - mAttachmentIcon.setVisibility(View.GONE); - - findViewById(R.id.reply).setOnClickListener(this); - findViewById(R.id.reply_all).setOnClickListener(this); - findViewById(R.id.delete).setOnClickListener(this); - findViewById(R.id.show_pictures).setOnClickListener(this); - - // UrlInterceptRegistry.registerHandler(this); - - mMessageContentView.getSettings().setBlockNetworkImage(true); - mMessageContentView.getSettings().setSupportZoom(false); - - setTitle(""); - - Intent intent = getIntent(); - mAccount = (Account) intent.getSerializableExtra(EXTRA_ACCOUNT); - mFolder = intent.getStringExtra(EXTRA_FOLDER); - mMessageUid = intent.getStringExtra(EXTRA_MESSAGE); - mFolderUids = intent.getStringArrayListExtra(EXTRA_FOLDER_UIDS); - - View next = findViewById(R.id.next); - View previous = findViewById(R.id.previous); - /* - * Next and Previous Message are not shown in landscape mode, so - * we need to check before we use them. - */ - if (next != null && previous != null) { - next.setOnClickListener(this); - previous.setOnClickListener(this); - - findSurroundingMessagesUid(); - - previous.setVisibility(mPreviousMessageUid != null ? View.VISIBLE : View.GONE); - next.setVisibility(mNextMessageUid != null ? View.VISIBLE : View.GONE); - - boolean goNext = intent.getBooleanExtra(EXTRA_NEXT, false); - if (goNext) { - next.requestFocus(); - } - } - - MessagingController.getInstance(getApplication()).addListener(mListener); - new Thread() { - public void run() { - // TODO this is a spot that should be eventually handled by a MessagingController - // thread pool. We want it in a thread but it can't be blocked by the normal - // synchronization stuff in MC. - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - MessagingController.getInstance(getApplication()).loadMessageForView( - mAccount, - mFolder, - mMessageUid, - mListener); - } - }.start(); - } - - private void findSurroundingMessagesUid() { - for (int i = 0, count = mFolderUids.size(); i < count; i++) { - String messageUid = mFolderUids.get(i); - if (messageUid.equals(mMessageUid)) { - if (i != 0) { - mPreviousMessageUid = mFolderUids.get(i - 1); - } - - if (i != count - 1) { - mNextMessageUid = mFolderUids.get(i + 1); - } - break; - } - } - } - - public void onResume() { - super.onResume(); - MessagingController.getInstance(getApplication()).addListener(mListener); - } - - public void onPause() { - super.onPause(); - MessagingController.getInstance(getApplication()).removeListener(mListener); - } - - private void onDelete() { - if (mMessage != null) { - MessagingController.getInstance(getApplication()).deleteMessage( - mAccount, - mFolder, - mMessage, - null); - Toast.makeText(this, R.string.message_deleted_toast, Toast.LENGTH_SHORT).show(); - - // Remove this message's Uid locally - mFolderUids.remove(mMessage.getUid()); - // Check if we have previous/next messages available before choosing - // which one to display - findSurroundingMessagesUid(); - - if (mPreviousMessageUid != null) { - onPrevious(); - } else if (mNextMessageUid != null) { - onNext(); - } else { - finish(); - } - } - } - - private void onReply() { - if (mMessage != null) { - MessageCompose.actionReply(this, mAccount, mMessage, false); - finish(); - } - } - - private void onReplyAll() { - if (mMessage != null) { - MessageCompose.actionReply(this, mAccount, mMessage, true); - finish(); - } - } - - private void onForward() { - if (mMessage != null) { - MessageCompose.actionForward(this, mAccount, mMessage); - finish(); - } - } - - private void onNext() { - Bundle extras = new Bundle(1); - extras.putBoolean(EXTRA_NEXT, true); - MessageView.actionView(this, mAccount, mFolder, mNextMessageUid, mFolderUids, extras); - finish(); - } - - private void onPrevious() { - MessageView.actionView(this, mAccount, mFolder, mPreviousMessageUid, mFolderUids); - finish(); - } - - private void onMarkAsUnread() { - MessagingController.getInstance(getApplication()).markMessageRead( - mAccount, - mFolder, - mMessage.getUid(), - false); - } - - /** - * Creates a unique file in the given directory by appending a hyphen - * and a number to the given filename. - * @param directory - * @param filename - * @return - */ - private File createUniqueFile(File directory, String filename) { - File file = new File(directory, filename); - if (!file.exists()) { - return file; - } - // Get the extension of the file, if any. - int index = filename.lastIndexOf('.'); - String format; - if (index != -1) { - String name = filename.substring(0, index); - String extension = filename.substring(index); - format = name + "-%d" + extension; - } - else { - format = filename + "-%d"; - } - for (int i = 2; i < Integer.MAX_VALUE; i++) { - file = new File(directory, String.format(format, i)); - if (!file.exists()) { - return file; - } - } - return null; - } - - private void onDownloadAttachment(Attachment attachment) { - if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - /* - * Abort early if there's no place to save the attachment. We don't want to spend - * the time downloading it and then abort. - */ - Toast.makeText(this, - getString(R.string.message_view_status_attachment_not_saved), - Toast.LENGTH_SHORT).show(); - return; - } - MessagingController.getInstance(getApplication()).loadAttachment( - mAccount, - mMessage, - attachment.part, - new Object[] { true, attachment }, - mListener); - } - - private void onViewAttachment(Attachment attachment) { - MessagingController.getInstance(getApplication()).loadAttachment( - mAccount, - mMessage, - attachment.part, - new Object[] { false, attachment }, - mListener); - } - - private void onShowPictures() { - mMessageContentView.getSettings().setBlockNetworkImage(false); - mShowPicturesSection.setVisibility(View.GONE); - } - - public void onClick(View view) { - switch (view.getId()) { - case R.id.reply: - onReply(); - break; - case R.id.reply_all: - onReplyAll(); - break; - case R.id.delete: - onDelete(); - break; - case R.id.next: - onNext(); - break; - case R.id.previous: - onPrevious(); - break; - case R.id.download: - onDownloadAttachment((Attachment) view.getTag()); - break; - case R.id.view: - onViewAttachment((Attachment) view.getTag()); - break; - case R.id.show_pictures: - onShowPictures(); - break; - } - } - - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.delete: - onDelete(); - break; - case R.id.reply: - onReply(); - break; - case R.id.reply_all: - onReplyAll(); - break; - case R.id.forward: - onForward(); - break; - case R.id.mark_as_unread: - onMarkAsUnread(); - break; - default: - return super.onOptionsItemSelected(item); - } - return true; - } - - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.message_view_option, menu); - return true; - } - - public CacheResult service(String url, Map headers) { - String prefix = "http://cid/"; - if (url.startsWith(prefix)) { - try { - String contentId = url.substring(prefix.length()); - final Part part = MimeUtility.findPartByContentId(mMessage, "<" + contentId + ">"); - if (part != null) { - CacheResult cr = new CacheManager.CacheResult(); - // TODO looks fixed in Mainline, cr.setInputStream - // part.getBody().writeTo(cr.getStream()); - return cr; - } - } - catch (Exception e) { - // TODO - } - } - return null; - } - - private Bitmap getPreviewIcon(Attachment attachment) throws MessagingException { - try { - return BitmapFactory.decodeStream( - getContentResolver().openInputStream( - AttachmentProvider.getAttachmentThumbnailUri(mAccount, - attachment.part.getAttachmentId(), - 62, - 62))); - } - catch (Exception e) { - /* - * We don't care what happened, we just return null for the preview icon. - */ - return null; - } - } - - /* - * Formats the given size as a String in bytes, kB, MB or GB with a single digit - * of precision. Ex: 12,315,000 = 12.3 MB - */ - public static String formatSize(float size) { - long kb = 1024; - long mb = (kb * 1024); - long gb = (mb * 1024); - if (size < kb) { - return String.format("%d bytes", (int) size); - } - else if (size < mb) { - return String.format("%.1f kB", size / kb); - } - else if (size < gb) { - return String.format("%.1f MB", size / mb); - } - else { - return String.format("%.1f GB", size / gb); - } - } - - private void renderAttachments(Part part, int depth) throws MessagingException { - String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); - String name = MimeUtility.getHeaderParameter(contentType, "name"); - if (name != null) { - /* - * We're guaranteed size because LocalStore.fetch puts it there. - */ - String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition()); - int size = Integer.parseInt(MimeUtility.getHeaderParameter(contentDisposition, "size")); - - Attachment attachment = new Attachment(); - attachment.size = size; - attachment.contentType = part.getMimeType(); - attachment.name = name; - attachment.part = (LocalAttachmentBodyPart) part; - - LayoutInflater inflater = getLayoutInflater(); - View view = inflater.inflate(R.layout.message_view_attachment, null); - - TextView attachmentName = (TextView)view.findViewById(R.id.attachment_name); - TextView attachmentInfo = (TextView)view.findViewById(R.id.attachment_info); - ImageView attachmentIcon = (ImageView)view.findViewById(R.id.attachment_icon); - Button attachmentView = (Button)view.findViewById(R.id.view); - Button attachmentDownload = (Button)view.findViewById(R.id.download); - - if ((!MimeUtility.mimeTypeMatches(attachment.contentType, - k9.ACCEPTABLE_ATTACHMENT_VIEW_TYPES)) - || (MimeUtility.mimeTypeMatches(attachment.contentType, - k9.UNACCEPTABLE_ATTACHMENT_VIEW_TYPES))) { - attachmentView.setVisibility(View.GONE); - } - if ((!MimeUtility.mimeTypeMatches(attachment.contentType, - k9.ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES)) - || (MimeUtility.mimeTypeMatches(attachment.contentType, - k9.UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES))) { - attachmentDownload.setVisibility(View.GONE); - } - - if (attachment.size > k9.MAX_ATTACHMENT_DOWNLOAD_SIZE) { - attachmentView.setVisibility(View.GONE); - attachmentDownload.setVisibility(View.GONE); - } - - attachment.viewButton = attachmentView; - attachment.downloadButton = attachmentDownload; - attachment.iconView = attachmentIcon; - - view.setTag(attachment); - attachmentView.setOnClickListener(this); - attachmentView.setTag(attachment); - attachmentDownload.setOnClickListener(this); - attachmentDownload.setTag(attachment); - - attachmentName.setText(name); - attachmentInfo.setText(formatSize(size)); - - Bitmap previewIcon = getPreviewIcon(attachment); - if (previewIcon != null) { - attachmentIcon.setImageBitmap(previewIcon); - } - - mHandler.addAttachment(view); - } - - if (part.getBody() instanceof Multipart) { - Multipart mp = (Multipart)part.getBody(); - for (int i = 0; i < mp.getCount(); i++) { - renderAttachments(mp.getBodyPart(i), depth + 1); - } - } - } - - class Listener extends MessagingListener { - - @Override - public void loadMessageForViewHeadersAvailable(Account account, String folder, String uid, - final Message message) { - MessageView.this.mMessage = message; - try { - String subjectText = message.getSubject(); - String fromText = Address.toFriendly(message.getFrom()); - String dateText = Utility.isDateToday(message.getSentDate()) ? - mTimeFormat.format(message.getSentDate()) : - mDateTimeFormat.format(message.getSentDate()); - String toText = Address.toFriendly(message.getRecipients(RecipientType.TO)); - boolean hasAttachments = ((LocalMessage) message).getAttachmentCount() > 0; - mHandler.setHeaders(subjectText, - fromText, - dateText, - toText, - hasAttachments); - } - catch (MessagingException me) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "loadMessageForViewHeadersAvailable", me); - } - } - } - - @Override - public void loadMessageForViewBodyAvailable(Account account, String folder, String uid, - Message message) { - SpannableString markup; - MessageView.this.mMessage = message; - try { - Part part = MimeUtility.findFirstPartByMimeType(mMessage, "text/html"); - if (part == null) { - part = MimeUtility.findFirstPartByMimeType(mMessage, "text/plain"); - } - if (part != null) { - String text = MimeUtility.getTextFromPart(part); - if (part.getMimeType().equalsIgnoreCase("text/html")) { - text = text.replaceAll("cid:", "http://cid/"); - } else { - /* - * Convert plain text to HTML by replacing - * \r?\n with
and adding a html/body wrapper. - */ - text = text.replaceAll("\r?\n", "
"); - text = "" + text + ""; - } - - - - /* - * TODO this should be smarter, change to regex for img, but consider how to - * get backgroung images and a million other things that HTML allows. - */ - if (text.contains(" 0) { - mDefaultView.setVisibility(View.VISIBLE); - } - - if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { - mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT); - } - - if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER)) { - mProvider = (Provider)savedInstanceState.getSerializable(STATE_KEY_PROVIDER); - } - } - - @Override - public void onResume() { - super.onResume(); - validateFields(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(EXTRA_ACCOUNT, mAccount); - if (mProvider != null) { - outState.putSerializable(STATE_KEY_PROVIDER, mProvider); - } - } - - public void afterTextChanged(Editable s) { - validateFields(); - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - private void validateFields() { - boolean valid = Utility.requiredFieldValid(mEmailView) - && Utility.requiredFieldValid(mPasswordView) - && mEmailValidator.isValid(mEmailView.getText().toString()); - mNextButton.setEnabled(valid); - mManualSetupButton.setEnabled(valid); - /* - * Dim the next button's icon to 50% if the button is disabled. - * TODO this can probably be done with a stateful drawable. Check into it. - * android:state_enabled - */ - Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128); - } - - private String getOwnerName() { - String name = null; - String projection[] = { - ContactMethods.NAME - }; - Cursor c = getContentResolver().query( - Uri.withAppendedPath(Contacts.People.CONTENT_URI, "owner"), projection, null, null, - null); - if (c.getCount() > 0) { - c.moveToFirst(); - name = c.getString(0); - c.close(); - } - - if (name == null || name.length() == 0) { - Account account = Preferences.getPreferences(this).getDefaultAccount(); - if (account != null) { - name = account.getName(); - } - } - return name; - } - - @Override - public Dialog onCreateDialog(int id) { - if (id == DIALOG_NOTE) { - if (mProvider != null && mProvider.note != null) { - return new AlertDialog.Builder(this) - .setMessage(mProvider.note) - .setPositiveButton( - getString(R.string.okay_action), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - finishAutoSetup(); - } - }) - .setNegativeButton( - getString(R.string.cancel_action), - null) - .create(); - } - } - return null; - } - - private void finishAutoSetup() { - String email = mEmailView.getText().toString(); - String password = mPasswordView.getText().toString(); - String[] emailParts = email.split("@"); - String user = emailParts[0]; - String domain = emailParts[1]; - URI incomingUri = null; - URI outgoingUri = null; - try { - String incomingUsername = mProvider.incomingUsernameTemplate; - incomingUsername = incomingUsername.replaceAll("\\$email", email); - incomingUsername = incomingUsername.replaceAll("\\$user", user); - incomingUsername = incomingUsername.replaceAll("\\$domain", domain); - - URI incomingUriTemplate = mProvider.incomingUriTemplate; - incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUsername + ":" - + password, incomingUriTemplate.getHost(), incomingUriTemplate.getPort(), null, - null, null); - - String outgoingUsername = mProvider.outgoingUsernameTemplate; - outgoingUsername = outgoingUsername.replaceAll("\\$email", email); - outgoingUsername = outgoingUsername.replaceAll("\\$user", user); - outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain); - - URI outgoingUriTemplate = mProvider.outgoingUriTemplate; - outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":" - + password, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null, - null, null); - } catch (URISyntaxException use) { - /* - * If there is some problem with the URI we give up and go on to - * manual setup. - */ - onManualSetup(); - return; - } - - mAccount = new Account(this); - mAccount.setName(getOwnerName()); - mAccount.setEmail(email); - mAccount.setStoreUri(incomingUri.toString()); - mAccount.setTransportUri(outgoingUri.toString()); - mAccount.setDraftsFolderName(getString(R.string.special_mailbox_name_drafts)); - mAccount.setTrashFolderName(getString(R.string.special_mailbox_name_trash)); - mAccount.setOutboxFolderName(getString(R.string.special_mailbox_name_outbox)); - mAccount.setSentFolderName(getString(R.string.special_mailbox_name_sent)); - if (incomingUri.toString().startsWith("imap")) { - mAccount.setDeletePolicy(Account.DELETE_POLICY_ON_DELETE); - } - AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, true); - } - - private void onNext() { - String email = mEmailView.getText().toString(); - String password = mPasswordView.getText().toString(); - String[] emailParts = email.split("@"); - String user = emailParts[0]; - String domain = emailParts[1]; - mProvider = findProviderForDomain(domain); - if (mProvider == null) { - /* - * We don't have default settings for this account, start the manual - * setup process. - */ - onManualSetup(); - return; - } - - if (mProvider.note != null) { - showDialog(DIALOG_NOTE); - } - else { - finishAutoSetup(); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) { - mAccount.setDescription(mAccount.getEmail()); - mAccount.save(Preferences.getPreferences(this)); - if (mDefaultView.isChecked()) { - Preferences.getPreferences(this).setDefaultAccount(mAccount); - } - k9.setServicesEnabled(this); - AccountSetupNames.actionSetNames(this, mAccount); - finish(); - } - } - - private void onManualSetup() { - String email = mEmailView.getText().toString(); - String password = mPasswordView.getText().toString(); - String[] emailParts = email.split("@"); - String user = emailParts[0]; - String domain = emailParts[1]; - - mAccount = new Account(this); - mAccount.setName(getOwnerName()); - mAccount.setEmail(email); - try { - URI uri = new URI("placeholder", user + ":" + password, "mail." + domain, -1, null, - null, null); - mAccount.setStoreUri(uri.toString()); - mAccount.setTransportUri(uri.toString()); - } catch (URISyntaxException use) { - /* - * If we can't set up the URL we just continue. It's only for - * convenience. - */ - } - mAccount.setDraftsFolderName(getString(R.string.special_mailbox_name_drafts)); - mAccount.setTrashFolderName(getString(R.string.special_mailbox_name_trash)); - mAccount.setOutboxFolderName(getString(R.string.special_mailbox_name_outbox)); - mAccount.setSentFolderName(getString(R.string.special_mailbox_name_sent)); - - AccountSetupAccountType.actionSelectAccountType(this, mAccount, mDefaultView.isChecked()); - finish(); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.next: - onNext(); - break; - case R.id.manual_setup: - onManualSetup(); - break; - } - } - - /** - * Attempts to get the given attribute as a String resource first, and if it fails - * returns the attribute as a simple String value. - * @param xml - * @param name - * @return - */ - private String getXmlAttribute(XmlResourceParser xml, String name) { - int resId = xml.getAttributeResourceValue(null, name, 0); - if (resId == 0) { - return xml.getAttributeValue(null, name); - } - else { - return getString(resId); - } - } - - private Provider findProviderForDomain(String domain) { - try { - XmlResourceParser xml = getResources().getXml(R.xml.providers); - int xmlEventType; - Provider provider = null; - while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) { - if (xmlEventType == XmlResourceParser.START_TAG - && "provider".equals(xml.getName()) - && domain.equalsIgnoreCase(getXmlAttribute(xml, "domain"))) { - provider = new Provider(); - provider.id = getXmlAttribute(xml, "id"); - provider.label = getXmlAttribute(xml, "label"); - provider.domain = getXmlAttribute(xml, "domain"); - provider.note = getXmlAttribute(xml, "note"); - } - else if (xmlEventType == XmlResourceParser.START_TAG - && "incoming".equals(xml.getName()) - && provider != null) { - provider.incomingUriTemplate = new URI(getXmlAttribute(xml, "uri")); - provider.incomingUsernameTemplate = getXmlAttribute(xml, "username"); - } - else if (xmlEventType == XmlResourceParser.START_TAG - && "outgoing".equals(xml.getName()) - && provider != null) { - provider.outgoingUriTemplate = new URI(getXmlAttribute(xml, "uri")); - provider.outgoingUsernameTemplate = getXmlAttribute(xml, "username"); - } - else if (xmlEventType == XmlResourceParser.END_TAG - && "provider".equals(xml.getName()) - && provider != null) { - return provider; - } - } - } - catch (Exception e) { - Log.e(k9.LOG_TAG, "Error while trying to load provider settings.", e); - } - return null; - } - - static class Provider implements Serializable { - private static final long serialVersionUID = 8511656164616538989L; - - public String id; - - public String label; - - public String domain; - - public URI incomingUriTemplate; - - public String incomingUsernameTemplate; - - public URI outgoingUriTemplate; - - public String outgoingUsernameTemplate; - - public String note; - } -} diff --git a/src/com/fsck/k9/activity/setup/AccountSetupCheckSettings.java b/src/com/fsck/k9/activity/setup/AccountSetupCheckSettings.java deleted file mode 100644 index ebc8a4b0a..000000000 --- a/src/com/fsck/k9/activity/setup/AccountSetupCheckSettings.java +++ /dev/null @@ -1,188 +0,0 @@ - -package com.fsck.k9.activity.setup; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Process; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.fsck.k9.Account; -import com.fsck.k9.R; -import com.fsck.k9.mail.AuthenticationFailedException; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.Transport; -import com.fsck.k9.mail.CertificateValidationException; - -/** - * Checks the given settings to make sure that they can be used to send and - * receive mail. - * - * XXX NOTE: The manifest for this app has it ignore config changes, because - * it doesn't correctly deal with restarting while its thread is running. - */ -public class AccountSetupCheckSettings extends Activity implements OnClickListener { - private static final String EXTRA_ACCOUNT = "account"; - - private static final String EXTRA_CHECK_INCOMING = "checkIncoming"; - - private static final String EXTRA_CHECK_OUTGOING = "checkOutgoing"; - - private Handler mHandler = new Handler(); - - private ProgressBar mProgressBar; - - private TextView mMessageView; - - private Account mAccount; - - private boolean mCheckIncoming; - - private boolean mCheckOutgoing; - - private boolean mCanceled; - - private boolean mDestroyed; - - public static void actionCheckSettings(Activity context, Account account, - boolean checkIncoming, boolean checkOutgoing) { - Intent i = new Intent(context, AccountSetupCheckSettings.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_CHECK_INCOMING, checkIncoming); - i.putExtra(EXTRA_CHECK_OUTGOING, checkOutgoing); - context.startActivityForResult(i, 1); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.account_setup_check_settings); - mMessageView = (TextView)findViewById(R.id.message); - mProgressBar = (ProgressBar)findViewById(R.id.progress); - ((Button)findViewById(R.id.cancel)).setOnClickListener(this); - - setMessage(R.string.account_setup_check_settings_retr_info_msg); - mProgressBar.setIndeterminate(true); - - mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); - mCheckIncoming = (boolean)getIntent().getBooleanExtra(EXTRA_CHECK_INCOMING, false); - mCheckOutgoing = (boolean)getIntent().getBooleanExtra(EXTRA_CHECK_OUTGOING, false); - - new Thread() { - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - try { - if (mDestroyed) { - return; - } - if (mCanceled) { - finish(); - return; - } - if (mCheckIncoming) { - setMessage(R.string.account_setup_check_settings_check_incoming_msg); - Store store = Store.getInstance(mAccount.getStoreUri(), getApplication()); - store.checkSettings(); - } - if (mDestroyed) { - return; - } - if (mCanceled) { - finish(); - return; - } - if (mCheckOutgoing) { - setMessage(R.string.account_setup_check_settings_check_outgoing_msg); - Transport transport = Transport.getInstance(mAccount.getTransportUri()); - transport.close(); - transport.open(); - transport.close(); - } - if (mDestroyed) { - return; - } - if (mCanceled) { - finish(); - return; - } - setResult(RESULT_OK); - finish(); - } catch (final AuthenticationFailedException afe) { - showErrorDialog( - R.string.account_setup_failed_dlg_auth_message_fmt, - afe.getMessage() == null ? "" : afe.getMessage()); - } catch (final CertificateValidationException cve) { - showErrorDialog( - R.string.account_setup_failed_dlg_certificate_message_fmt, - cve.getMessage() == null ? "" : cve.getMessage()); - } catch (final MessagingException me) { - showErrorDialog( - R.string.account_setup_failed_dlg_server_message_fmt, - me.getMessage() == null ? "" : me.getMessage()); - } - } - }.start(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mDestroyed = true; - mCanceled = true; - } - - private void setMessage(final int resId) { - mHandler.post(new Runnable() { - public void run() { - if (mDestroyed) { - return; - } - mMessageView.setText(getString(resId)); - } - }); - } - - private void showErrorDialog(final int msgResId, final Object... args) { - mHandler.post(new Runnable() { - public void run() { - if (mDestroyed) { - return; - } - mProgressBar.setIndeterminate(false); - new AlertDialog.Builder(AccountSetupCheckSettings.this) - .setTitle(getString(R.string.account_setup_failed_dlg_title)) - .setMessage(getString(msgResId, args)) - .setCancelable(true) - .setPositiveButton( - getString(R.string.account_setup_failed_dlg_edit_details_action), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }) - .show(); - } - }); - } - - private void onCancel() { - mCanceled = true; - setMessage(R.string.account_setup_check_settings_canceling_msg); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.cancel: - onCancel(); - break; - } - } -} diff --git a/src/com/fsck/k9/activity/setup/AccountSetupComposition.java b/src/com/fsck/k9/activity/setup/AccountSetupComposition.java deleted file mode 100644 index cb450b0a9..000000000 --- a/src/com/fsck/k9/activity/setup/AccountSetupComposition.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.fsck.k9.activity.setup; - -import android.app.Activity; -import android.content.Intent; -import android.content.SharedPreferences; -import android.util.Log; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.View; -import android.view.KeyEvent; -import android.widget.AdapterView; -import android.widget.EditText; -import android.widget.TextView; - -import com.fsck.k9.Account; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; -import com.fsck.k9.k9; -import com.fsck.k9.Utility; - -public class AccountSetupComposition extends Activity { - - private static final String EXTRA_ACCOUNT = "account"; - - private Account mAccount; - - private EditText mAccountSignature; - private EditText mAccountEmail; - private EditText mAccountAlwaysBcc; - private EditText mAccountName; - - - - public static void actionEditCompositionSettings(Activity context, Account account) { - Intent i = new Intent(context, AccountSetupComposition.class); - i.setAction(Intent.ACTION_EDIT); - i.putExtra(EXTRA_ACCOUNT, account); - context.startActivity(i); - } - - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); - - setContentView(R.layout.account_setup_composition); - - /* - * If we're being reloaded we override the original account with the one - * we saved - */ - if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { - mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT); - } - - mAccountName = (EditText)findViewById(R.id.account_name); - mAccountName.setText(mAccount.getName()); - - mAccountEmail = (EditText)findViewById(R.id.account_email); - mAccountEmail.setText(mAccount.getEmail()); - - mAccountAlwaysBcc = (EditText)findViewById(R.id.account_always_bcc); - mAccountAlwaysBcc.setText(mAccount.getAlwaysBcc()); - - mAccountSignature = (EditText)findViewById(R.id.account_signature); - mAccountSignature.setText(mAccount.getSignature()); - - } - - @Override - public void onResume() { - super.onResume(); - mAccount.refresh(Preferences.getPreferences(this)); - } - - private void saveSettings() { - mAccount.setEmail(mAccountEmail.getText().toString()); - mAccount.setAlwaysBcc(mAccountAlwaysBcc.getText().toString()); - mAccount.setName(mAccountName.getText().toString()); - mAccount.setSignature(mAccountSignature.getText().toString()); - - mAccount.save(Preferences.getPreferences(this)); - - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - saveSettings(); - } - return super.onKeyDown(keyCode, event); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(EXTRA_ACCOUNT, mAccount); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - mAccount.save(Preferences.getPreferences(this)); - finish(); - } -} diff --git a/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java b/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java deleted file mode 100644 index d5ee5b029..000000000 --- a/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java +++ /dev/null @@ -1,325 +0,0 @@ - -package com.fsck.k9.activity.setup; - -import java.net.URI; -import java.net.URISyntaxException; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.text.method.DigitsKeyListener; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TextView; - -import com.fsck.k9.Account; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; -import com.fsck.k9.Utility; - -public class AccountSetupIncoming extends Activity implements OnClickListener { - private static final String EXTRA_ACCOUNT = "account"; - private static final String EXTRA_MAKE_DEFAULT = "makeDefault"; - - private static final int popPorts[] = { - 110, 995, 995, 110, 110 - }; - private static final String popSchemes[] = { - "pop3", "pop3+ssl", "pop3+ssl+", "pop3+tls", "pop3+tls+" - }; - private static final int imapPorts[] = { - 143, 993, 993, 143, 143 - }; - private static final String imapSchemes[] = { - "imap", "imap+ssl", "imap+ssl+", "imap+tls", "imap+tls+" - }; - - private int mAccountPorts[]; - private String mAccountSchemes[]; - private EditText mUsernameView; - private EditText mPasswordView; - private EditText mServerView; - private EditText mPortView; - private Spinner mSecurityTypeView; - private Spinner mDeletePolicyView; - private EditText mImapPathPrefixView; - private Button mNextButton; - private Account mAccount; - private boolean mMakeDefault; - - public static void actionIncomingSettings(Activity context, Account account, boolean makeDefault) { - Intent i = new Intent(context, AccountSetupIncoming.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault); - context.startActivity(i); - } - - public static void actionEditIncomingSettings(Activity context, Account account) { - Intent i = new Intent(context, AccountSetupIncoming.class); - i.setAction(Intent.ACTION_EDIT); - i.putExtra(EXTRA_ACCOUNT, account); - context.startActivity(i); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.account_setup_incoming); - - mUsernameView = (EditText)findViewById(R.id.account_username); - mPasswordView = (EditText)findViewById(R.id.account_password); - TextView serverLabelView = (TextView) findViewById(R.id.account_server_label); - mServerView = (EditText)findViewById(R.id.account_server); - mPortView = (EditText)findViewById(R.id.account_port); - mSecurityTypeView = (Spinner)findViewById(R.id.account_security_type); - mDeletePolicyView = (Spinner)findViewById(R.id.account_delete_policy); - mImapPathPrefixView = (EditText)findViewById(R.id.imap_path_prefix); - mNextButton = (Button)findViewById(R.id.next); - - mNextButton.setOnClickListener(this); - - SpinnerOption securityTypes[] = { - new SpinnerOption(0, getString(R.string.account_setup_incoming_security_none_label)), - new SpinnerOption(1, - getString(R.string.account_setup_incoming_security_ssl_optional_label)), - new SpinnerOption(2, getString(R.string.account_setup_incoming_security_ssl_label)), - new SpinnerOption(3, - getString(R.string.account_setup_incoming_security_tls_optional_label)), - new SpinnerOption(4, getString(R.string.account_setup_incoming_security_tls_label)), - }; - - SpinnerOption deletePolicies[] = { - new SpinnerOption(0, - getString(R.string.account_setup_incoming_delete_policy_never_label)), - new SpinnerOption(1, - getString(R.string.account_setup_incoming_delete_policy_7days_label)), - new SpinnerOption(2, - getString(R.string.account_setup_incoming_delete_policy_delete_label)), - }; - - ArrayAdapter securityTypesAdapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_item, securityTypes); - securityTypesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mSecurityTypeView.setAdapter(securityTypesAdapter); - - ArrayAdapter deletePoliciesAdapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_item, deletePolicies); - deletePoliciesAdapter - .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mDeletePolicyView.setAdapter(deletePoliciesAdapter); - - /* - * Updates the port when the user changes the security type. This allows - * us to show a reasonable default which the user can change. - */ - mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) { - updatePortFromSecurityType(); - } - - public void onNothingSelected(AdapterView arg0) { - } - }); - - /* - * Calls validateFields() which enables or disables the Next button - * based on the fields' validity. - */ - TextWatcher validationTextWatcher = new TextWatcher() { - public void afterTextChanged(Editable s) { - validateFields(); - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }; - mUsernameView.addTextChangedListener(validationTextWatcher); - mPasswordView.addTextChangedListener(validationTextWatcher); - mServerView.addTextChangedListener(validationTextWatcher); - mPortView.addTextChangedListener(validationTextWatcher); - - /* - * Only allow digits in the port field. - */ - mPortView.setKeyListener(DigitsKeyListener.getInstance("0123456789")); - - mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); - mMakeDefault = (boolean)getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false); - - /* - * If we're being reloaded we override the original account with the one - * we saved - */ - if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { - mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT); - } - - try { - URI uri = new URI(mAccount.getStoreUri()); - String username = null; - String password = null; - if (uri.getUserInfo() != null) { - String[] userInfoParts = uri.getUserInfo().split(":", 2); - username = userInfoParts[0]; - if (userInfoParts.length > 1) { - password = userInfoParts[1]; - } - } - - if (username != null) { - mUsernameView.setText(username); - } - - if (password != null) { - mPasswordView.setText(password); - } - - if (uri.getScheme().startsWith("pop3")) { - serverLabelView.setText(R.string.account_setup_incoming_pop_server_label); - mAccountPorts = popPorts; - mAccountSchemes = popSchemes; - - findViewById(R.id.imap_path_prefix_section).setVisibility(View.GONE); - } else if (uri.getScheme().startsWith("imap")) { - serverLabelView.setText(R.string.account_setup_incoming_imap_server_label); - mAccountPorts = imapPorts; - mAccountSchemes = imapSchemes; - - findViewById(R.id.account_delete_policy_label).setVisibility(View.GONE); - mDeletePolicyView.setVisibility(View.GONE); - if (uri.getPath() != null && uri.getPath().length() > 0) { - mImapPathPrefixView.setText(uri.getPath().substring(1)); - } - } else { - throw new Error("Unknown account type: " + mAccount.getStoreUri()); - } - - for (int i = 0; i < mAccountSchemes.length; i++) { - if (mAccountSchemes[i].equals(uri.getScheme())) { - SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, i); - } - } - - SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, mAccount.getDeletePolicy()); - - if (uri.getHost() != null) { - mServerView.setText(uri.getHost()); - } - - if (uri.getPort() != -1) { - mPortView.setText(Integer.toString(uri.getPort())); - } else { - updatePortFromSecurityType(); - } - } catch (URISyntaxException use) { - /* - * We should always be able to parse our own settings. - */ - throw new Error(use); - } - - validateFields(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(EXTRA_ACCOUNT, mAccount); - } - - private void validateFields() { - mNextButton - .setEnabled(Utility.requiredFieldValid(mUsernameView) - && Utility.requiredFieldValid(mPasswordView) - && Utility.requiredFieldValid(mServerView) - && Utility.requiredFieldValid(mPortView)); - Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128); - } - - private void updatePortFromSecurityType() { - int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value; - mPortView.setText(Integer.toString(mAccountPorts[securityType])); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) { - if (Intent.ACTION_EDIT.equals(getIntent().getAction())) { - mAccount.save(Preferences.getPreferences(this)); - finish(); - } else { - /* - * Set the username and password for the outgoing settings to the username and - * password the user just set for incoming. - */ - try { - URI oldUri = new URI(mAccount.getTransportUri()); - URI uri = new URI( - oldUri.getScheme(), - mUsernameView.getText() + ":" + mPasswordView.getText(), - oldUri.getHost(), - oldUri.getPort(), - null, - null, - null); - mAccount.setTransportUri(uri.toString()); - } catch (URISyntaxException use) { - /* - * If we can't set up the URL we just continue. It's only for - * convenience. - */ - } - - - AccountSetupOutgoing.actionOutgoingSettings(this, mAccount, mMakeDefault); - finish(); - } - } - } - - private void onNext() { - int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value; - try { - String path = null; - if (mAccountSchemes[securityType].startsWith("imap")) { - path = "/" + mImapPathPrefixView.getText(); - } - URI uri = new URI( - mAccountSchemes[securityType], - mUsernameView.getText() + ":" + mPasswordView.getText(), - mServerView.getText().toString(), - Integer.parseInt(mPortView.getText().toString()), - path, // path - null, // query - null); - mAccount.setStoreUri(uri.toString()); - } catch (URISyntaxException use) { - /* - * It's unrecoverable if we cannot create a URI from components that - * we validated to be safe. - */ - throw new Error(use); - } - - mAccount.setDeletePolicy((Integer)((SpinnerOption)mDeletePolicyView.getSelectedItem()).value); - AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.next: - onNext(); - break; - } - } -} diff --git a/src/com/fsck/k9/activity/setup/AccountSetupNames.java b/src/com/fsck/k9/activity/setup/AccountSetupNames.java deleted file mode 100644 index 65706aaba..000000000 --- a/src/com/fsck/k9/activity/setup/AccountSetupNames.java +++ /dev/null @@ -1,103 +0,0 @@ - -package com.fsck.k9.activity.setup; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.text.method.TextKeyListener; -import android.text.method.TextKeyListener.Capitalize; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.EditText; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; -import com.fsck.k9.Utility; -import com.fsck.k9.activity.FolderMessageList; - -public class AccountSetupNames extends Activity implements OnClickListener { - private static final String EXTRA_ACCOUNT = "account"; - - private EditText mDescription; - - private EditText mName; - - private Account mAccount; - - private Button mDoneButton; - - public static void actionSetNames(Context context, Account account) { - Intent i = new Intent(context, AccountSetupNames.class); - i.putExtra(EXTRA_ACCOUNT, account); - context.startActivity(i); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.account_setup_names); - mDescription = (EditText)findViewById(R.id.account_description); - mName = (EditText)findViewById(R.id.account_name); - mDoneButton = (Button)findViewById(R.id.done); - mDoneButton.setOnClickListener(this); - - TextWatcher validationTextWatcher = new TextWatcher() { - public void afterTextChanged(Editable s) { - validateFields(); - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }; - mName.addTextChangedListener(validationTextWatcher); - - mName.setKeyListener(TextKeyListener.getInstance(false, Capitalize.WORDS)); - - mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); - - /* - * Since this field is considered optional, we don't set this here. If - * the user fills in a value we'll reset the current value, otherwise we - * just leave the saved value alone. - */ - // mDescription.setText(mAccount.getDescription()); - if (mAccount.getName() != null) { - mName.setText(mAccount.getName()); - } - if (!Utility.requiredFieldValid(mName)) { - mDoneButton.setEnabled(false); - } - } - - private void validateFields() { - mDoneButton.setEnabled(Utility.requiredFieldValid(mName)); - Utility.setCompoundDrawablesAlpha(mDoneButton, mDoneButton.isEnabled() ? 255 : 128); - } - - private void onNext() { - if (Utility.requiredFieldValid(mDescription)) { - mAccount.setDescription(mDescription.getText().toString()); - } - mAccount.setName(mName.getText().toString()); - mAccount.save(Preferences.getPreferences(this)); - FolderMessageList.actionHandleAccount(this, mAccount, k9.INBOX); - finish(); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.done: - onNext(); - break; - } - } -} diff --git a/src/com/fsck/k9/activity/setup/AccountSetupOptions.java b/src/com/fsck/k9/activity/setup/AccountSetupOptions.java deleted file mode 100644 index ebaa74830..000000000 --- a/src/com/fsck/k9/activity/setup/AccountSetupOptions.java +++ /dev/null @@ -1,103 +0,0 @@ - -package com.fsck.k9.activity.setup; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.Spinner; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; - -public class AccountSetupOptions extends Activity implements OnClickListener { - private static final String EXTRA_ACCOUNT = "account"; - - private static final String EXTRA_MAKE_DEFAULT = "makeDefault"; - - private Spinner mCheckFrequencyView; - - private CheckBox mDefaultView; - - private CheckBox mNotifyView; - - private Account mAccount; - - public static void actionOptions(Context context, Account account, boolean makeDefault) { - Intent i = new Intent(context, AccountSetupOptions.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault); - context.startActivity(i); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.account_setup_options); - - mCheckFrequencyView = (Spinner)findViewById(R.id.account_check_frequency); - mDefaultView = (CheckBox)findViewById(R.id.account_default); - mNotifyView = (CheckBox)findViewById(R.id.account_notify); - - findViewById(R.id.next).setOnClickListener(this); - - SpinnerOption checkFrequencies[] = { - new SpinnerOption(-1, - getString(R.string.account_setup_options_mail_check_frequency_never)), - new SpinnerOption(5, - getString(R.string.account_setup_options_mail_check_frequency_5min)), - new SpinnerOption(10, - getString(R.string.account_setup_options_mail_check_frequency_10min)), - new SpinnerOption(15, - getString(R.string.account_setup_options_mail_check_frequency_15min)), - new SpinnerOption(30, - getString(R.string.account_setup_options_mail_check_frequency_30min)), - new SpinnerOption(60, - getString(R.string.account_setup_options_mail_check_frequency_1hour)), - }; - - ArrayAdapter checkFrequenciesAdapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_item, checkFrequencies); - checkFrequenciesAdapter - .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mCheckFrequencyView.setAdapter(checkFrequenciesAdapter); - - mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); - boolean makeDefault = getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false); - - if (mAccount.equals(Preferences.getPreferences(this).getDefaultAccount()) || makeDefault) { - mDefaultView.setChecked(true); - } - mNotifyView.setChecked(mAccount.isNotifyNewMail()); - SpinnerOption.setSpinnerOptionValue(mCheckFrequencyView, mAccount - .getAutomaticCheckIntervalMinutes()); - } - - private void onDone() { - mAccount.setDescription(mAccount.getEmail()); - mAccount.setNotifyNewMail(mNotifyView.isChecked()); - mAccount.setAutomaticCheckIntervalMinutes((Integer)((SpinnerOption)mCheckFrequencyView - .getSelectedItem()).value); - mAccount.save(Preferences.getPreferences(this)); - if (mDefaultView.isChecked()) { - Preferences.getPreferences(this).setDefaultAccount(mAccount); - } - k9.setServicesEnabled(this); - AccountSetupNames.actionSetNames(this, mAccount); - finish(); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.next: - onDone(); - break; - } - } -} diff --git a/src/com/fsck/k9/activity/setup/AccountSetupOutgoing.java b/src/com/fsck/k9/activity/setup/AccountSetupOutgoing.java deleted file mode 100644 index dfc547070..000000000 --- a/src/com/fsck/k9/activity/setup/AccountSetupOutgoing.java +++ /dev/null @@ -1,266 +0,0 @@ - -package com.fsck.k9.activity.setup; - -import java.net.URI; -import java.net.URISyntaxException; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.text.method.DigitsKeyListener; -import android.view.View; -import android.view.ViewGroup; -import android.view.View.OnClickListener; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.CompoundButton.OnCheckedChangeListener; - -import com.fsck.k9.Account; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; -import com.fsck.k9.Utility; - -public class AccountSetupOutgoing extends Activity implements OnClickListener, - OnCheckedChangeListener { - private static final String EXTRA_ACCOUNT = "account"; - - private static final String EXTRA_MAKE_DEFAULT = "makeDefault"; - - private static final int smtpPorts[] = { - 25, 465, 465, 25, 25 - }; - - private static final String smtpSchemes[] = { - "smtp", "smtp+ssl", "smtp+ssl+", "smtp+tls", "smtp+tls+" - }; - - private EditText mUsernameView; - private EditText mPasswordView; - private EditText mServerView; - private EditText mPortView; - private CheckBox mRequireLoginView; - private ViewGroup mRequireLoginSettingsView; - private Spinner mSecurityTypeView; - private Button mNextButton; - private Account mAccount; - private boolean mMakeDefault; - - public static void actionOutgoingSettings(Context context, Account account, boolean makeDefault) { - Intent i = new Intent(context, AccountSetupOutgoing.class); - i.putExtra(EXTRA_ACCOUNT, account); - i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault); - context.startActivity(i); - } - - public static void actionEditOutgoingSettings(Context context, Account account) { - Intent i = new Intent(context, AccountSetupOutgoing.class); - i.setAction(Intent.ACTION_EDIT); - i.putExtra(EXTRA_ACCOUNT, account); - context.startActivity(i); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.account_setup_outgoing); - - mUsernameView = (EditText)findViewById(R.id.account_username); - mPasswordView = (EditText)findViewById(R.id.account_password); - mServerView = (EditText)findViewById(R.id.account_server); - mPortView = (EditText)findViewById(R.id.account_port); - mRequireLoginView = (CheckBox)findViewById(R.id.account_require_login); - mRequireLoginSettingsView = (ViewGroup)findViewById(R.id.account_require_login_settings); - mSecurityTypeView = (Spinner)findViewById(R.id.account_security_type); - mNextButton = (Button)findViewById(R.id.next); - - mNextButton.setOnClickListener(this); - mRequireLoginView.setOnCheckedChangeListener(this); - - SpinnerOption securityTypes[] = { - new SpinnerOption(0, getString(R.string.account_setup_incoming_security_none_label)), - new SpinnerOption(1, - getString(R.string.account_setup_incoming_security_ssl_optional_label)), - new SpinnerOption(2, getString(R.string.account_setup_incoming_security_ssl_label)), - new SpinnerOption(3, - getString(R.string.account_setup_incoming_security_tls_optional_label)), - new SpinnerOption(4, getString(R.string.account_setup_incoming_security_tls_label)), - }; - - ArrayAdapter securityTypesAdapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_item, securityTypes); - securityTypesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mSecurityTypeView.setAdapter(securityTypesAdapter); - - /* - * Updates the port when the user changes the security type. This allows - * us to show a reasonable default which the user can change. - */ - mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) { - updatePortFromSecurityType(); - } - - public void onNothingSelected(AdapterView arg0) { - } - }); - - /* - * Calls validateFields() which enables or disables the Next button - * based on the fields' validity. - */ - TextWatcher validationTextWatcher = new TextWatcher() { - public void afterTextChanged(Editable s) { - validateFields(); - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }; - mUsernameView.addTextChangedListener(validationTextWatcher); - mPasswordView.addTextChangedListener(validationTextWatcher); - mServerView.addTextChangedListener(validationTextWatcher); - mPortView.addTextChangedListener(validationTextWatcher); - - /* - * Only allow digits in the port field. - */ - mPortView.setKeyListener(DigitsKeyListener.getInstance("0123456789")); - - mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); - mMakeDefault = (boolean)getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false); - - /* - * If we're being reloaded we override the original account with the one - * we saved - */ - if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { - mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT); - } - - try { - URI uri = new URI(mAccount.getTransportUri()); - String username = null; - String password = null; - if (uri.getUserInfo() != null) { - String[] userInfoParts = uri.getUserInfo().split(":", 2); - username = userInfoParts[0]; - if (userInfoParts.length > 1) { - password = userInfoParts[1]; - } - } - - if (username != null) { - mUsernameView.setText(username); - mRequireLoginView.setChecked(true); - } - - if (password != null) { - mPasswordView.setText(password); - } - - for (int i = 0; i < smtpSchemes.length; i++) { - if (smtpSchemes[i].equals(uri.getScheme())) { - SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, i); - } - } - - if (uri.getHost() != null) { - mServerView.setText(uri.getHost()); - } - - if (uri.getPort() != -1) { - mPortView.setText(Integer.toString(uri.getPort())); - } else { - updatePortFromSecurityType(); - } - } catch (URISyntaxException use) { - /* - * We should always be able to parse our own settings. - */ - throw new Error(use); - } - - validateFields(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(EXTRA_ACCOUNT, mAccount); - } - - private void validateFields() { - mNextButton - .setEnabled( - Utility.requiredFieldValid(mServerView) && - Utility.requiredFieldValid(mPortView) && - (!mRequireLoginView.isChecked() || - (Utility.requiredFieldValid(mUsernameView) && - Utility.requiredFieldValid(mPasswordView)))); - Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128); - } - - private void updatePortFromSecurityType() { - int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value; - mPortView.setText(Integer.toString(smtpPorts[securityType])); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) { - if (Intent.ACTION_EDIT.equals(getIntent().getAction())) { - mAccount.save(Preferences.getPreferences(this)); - finish(); - } else { - AccountSetupOptions.actionOptions(this, mAccount, mMakeDefault); - finish(); - } - } - } - - private void onNext() { - int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value; - URI uri; - try { - String userInfo = null; - if (mRequireLoginView.isChecked()) { - userInfo = mUsernameView.getText().toString() + ":" - + mPasswordView.getText().toString(); - } - uri = new URI(smtpSchemes[securityType], userInfo, mServerView.getText().toString(), - Integer.parseInt(mPortView.getText().toString()), null, null, null); - mAccount.setTransportUri(uri.toString()); - } catch (URISyntaxException use) { - /* - * It's unrecoverable if we cannot create a URI from components that - * we validated to be safe. - */ - throw new Error(use); - } - AccountSetupCheckSettings.actionCheckSettings(this, mAccount, false, true); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.next: - onNext(); - break; - } - } - - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - mRequireLoginSettingsView.setVisibility(isChecked ? View.VISIBLE : View.GONE); - validateFields(); - } -} diff --git a/src/com/fsck/k9/activity/setup/SpinnerOption.java b/src/com/fsck/k9/activity/setup/SpinnerOption.java deleted file mode 100644 index f97a95249..000000000 --- a/src/com/fsck/k9/activity/setup/SpinnerOption.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * - */ - -package com.fsck.k9.activity.setup; - -import android.widget.Spinner; - -public class SpinnerOption { - public Object value; - - public String label; - - public static void setSpinnerOptionValue(Spinner spinner, Object value) { - for (int i = 0, count = spinner.getCount(); i < count; i++) { - SpinnerOption so = (SpinnerOption)spinner.getItemAtPosition(i); - if (so.value.equals(value)) { - spinner.setSelection(i, true); - return; - } - } - } - - public SpinnerOption(Object value, String label) { - this.value = value; - this.label = label; - } - - @Override - public String toString() { - return label; - } -} diff --git a/src/com/fsck/k9/codec/binary/Base64.java b/src/com/fsck/k9/codec/binary/Base64.java deleted file mode 100644 index ba5b03126..000000000 --- a/src/com/fsck/k9/codec/binary/Base64.java +++ /dev/null @@ -1,788 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.fsck.k9.codec.binary; - -import org.apache.commons.codec.BinaryDecoder; -import org.apache.commons.codec.BinaryEncoder; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; - -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; - -/** - * Provides Base64 encoding and decoding as defined by RFC 2045. - * - *

- * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose - * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein. - *

- * - * @see
RFC 2045 - * @author Apache Software Foundation - * @since 1.0-dev - * @version $Id$ - */ -public class Base64 implements BinaryEncoder, BinaryDecoder { - /** - * Chunk size per RFC 2045 section 6.8. - * - *

- * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any - * equal signs. - *

- * - * @see RFC 2045 section 6.8 - */ - static final int CHUNK_SIZE = 76; - - /** - * Chunk separator per RFC 2045 section 2.1. - * - * @see RFC 2045 section 2.1 - */ - static final byte[] CHUNK_SEPARATOR = {'\r','\n'}; - - /** - * This array is a lookup table that translates 6-bit positive integer - * index values into their "Base64 Alphabet" equivalents as specified - * in Table 1 of RFC 2045. - * - * Thanks to "commons" project in ws.apache.org for this code. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - */ - private static final byte[] intToBase64 = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' - }; - - /** - * Byte used to pad output. - */ - private static final byte PAD = '='; - - /** - * This array is a lookup table that translates unicode characters - * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045) - * into their 6-bit positive integer equivalents. Characters that - * are not in the Base64 alphabet but fall within the bounds of the - * array are translated to -1. - * - * Thanks to "commons" project in ws.apache.org for this code. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - */ - private static final byte[] base64ToInt = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - }; - - /** Mask used to extract 6 bits, used when encoding */ - private static final int MASK_6BITS = 0x3f; - - /** Mask used to extract 8 bits, used in decoding base64 bytes */ - private static final int MASK_8BITS = 0xff; - - // The static final fields above are used for the original static byte[] methods on Base64. - // The private member fields below are used with the new streaming approach, which requires - // some state be preserved between calls of encode() and decode(). - - - /** - * Line length for encoding. Not used when decoding. A value of zero or less implies - * no chunking of the base64 encoded data. - */ - private final int lineLength; - - /** - * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. - */ - private final byte[] lineSeparator; - - /** - * Convenience variable to help us determine when our buffer is going to run out of - * room and needs resizing. decodeSize = 3 + lineSeparator.length; - */ - private final int decodeSize; - - /** - * Convenience variable to help us determine when our buffer is going to run out of - * room and needs resizing. encodeSize = 4 + lineSeparator.length; - */ - private final int encodeSize; - - /** - * Buffer for streaming. - */ - private byte[] buf; - - /** - * Position where next character should be written in the buffer. - */ - private int pos; - - /** - * Position where next character should be read from the buffer. - */ - private int readPos; - - /** - * Variable tracks how many characters have been written to the current line. - * Only used when encoding. We use it to make sure each encoded line never - * goes beyond lineLength (if lineLength > 0). - */ - private int currentLinePos; - - /** - * Writes to the buffer only occur after every 3 reads when encoding, an - * every 4 reads when decoding. This variable helps track that. - */ - private int modulus; - - /** - * Boolean flag to indicate the EOF has been reached. Once EOF has been - * reached, this Base64 object becomes useless, and must be thrown away. - */ - private boolean eof; - - /** - * Place holder for the 3 bytes we're dealing with for our base64 logic. - * Bitwise operations store and extract the base64 encoding or decoding from - * this variable. - */ - private int x; - - /** - * Default constructor: lineLength is 76, and the lineSeparator is CRLF - * when encoding, and all forms can be decoded. - */ - public Base64() { - this(CHUNK_SIZE, CHUNK_SEPARATOR); - } - - /** - *

- * Consumer can use this constructor to choose a different lineLength - * when encoding (lineSeparator is still CRLF). All forms of data can - * be decoded. - *

- * Note: lineLengths that aren't multiples of 4 will still essentially - * end up being multiples of 4 in the encoded data. - *

- * - * @param lineLength each line of encoded data will be at most this long - * (rounded up to nearest multiple of 4). - * If lineLength <= 0, then the output will not be divided into lines (chunks). - * Ignored when decoding. - */ - public Base64(int lineLength) { - this(lineLength, CHUNK_SEPARATOR); - } - - /** - *

- * Consumer can use this constructor to choose a different lineLength - * and lineSeparator when encoding. All forms of data can - * be decoded. - *

- * Note: lineLengths that aren't multiples of 4 will still essentially - * end up being multiples of 4 in the encoded data. - *

- * @param lineLength Each line of encoded data will be at most this long - * (rounded up to nearest multiple of 4). Ignored when decoding. - * If <= 0, then output will not be divided into lines (chunks). - * @param lineSeparator Each line of encoded data will end with this - * sequence of bytes. - * If lineLength <= 0, then the lineSeparator is not used. - * @throws IllegalArgumentException The provided lineSeparator included - * some base64 characters. That's not going to work! - */ - public Base64(int lineLength, byte[] lineSeparator) { - this.lineLength = lineLength; - this.lineSeparator = new byte[lineSeparator.length]; - System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length); - if (lineLength > 0) { - this.encodeSize = 4 + lineSeparator.length; - } else { - this.encodeSize = 4; - } - this.decodeSize = encodeSize - 1; - if (containsBase64Byte(lineSeparator)) { - String sep; - try { - sep = new String(lineSeparator, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - sep = new String(lineSeparator); - } - throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]"); - } - } - - /** - * Returns true if this Base64 object has buffered data for reading. - * - * @return true if there is Base64 object still available for reading. - */ - boolean hasData() { return buf != null; } - - /** - * Returns the amount of buffered data available for reading. - * - * @return The amount of buffered data available for reading. - */ - int avail() { return buf != null ? pos - readPos : 0; } - - /** Doubles our buffer. */ - private void resizeBuf() { - if (buf == null) { - buf = new byte[8192]; - pos = 0; - readPos = 0; - } else { - byte[] b = new byte[buf.length * 2]; - System.arraycopy(buf, 0, b, 0, buf.length); - buf = b; - } - } - - /** - * Extracts buffered data into the provided byte[] array, starting - * at position bPos, up to a maximum of bAvail bytes. Returns how - * many bytes were actually extracted. - * - * @param b byte[] array to extract the buffered data into. - * @param bPos position in byte[] array to start extraction at. - * @param bAvail amount of bytes we're allowed to extract. We may extract - * fewer (if fewer are available). - * @return The number of bytes successfully extracted into the provided - * byte[] array. - */ - int readResults(byte[] b, int bPos, int bAvail) { - if (buf != null) { - int len = Math.min(avail(), bAvail); - if (buf != b) { - System.arraycopy(buf, readPos, b, bPos, len); - readPos += len; - if (readPos >= pos) { - buf = null; - } - } else { - // Re-using the original consumer's output array is only - // allowed for one round. - buf = null; - } - return len; - } else { - return eof ? -1 : 0; - } - } - - /** - * Small optimization where we try to buffer directly to the consumer's - * output array for one round (if consumer calls this method first!) instead - * of starting our own buffer. - * - * @param out byte[] array to buffer directly to. - * @param outPos Position to start buffering into. - * @param outAvail Amount of bytes available for direct buffering. - */ - void setInitialBuffer(byte[] out, int outPos, int outAvail) { - // We can re-use consumer's original output array under - // special circumstances, saving on some System.arraycopy(). - if (out != null && out.length == outAvail) { - buf = out; - pos = outPos; - readPos = outPos; - } - } - - /** - *

- * Encodes all of the provided data, starting at inPos, for inAvail bytes. - * Must be called at least twice: once with the data to encode, and once - * with inAvail set to "-1" to alert encoder that EOF has been reached, - * so flush last remaining bytes (if not multiple of 3). - *

- * Thanks to "commons" project in ws.apache.org for the bitwise operations, - * and general approach. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - *

- * - * @param in byte[] array of binary data to base64 encode. - * @param inPos Position to start reading data from. - * @param inAvail Amount of bytes available from input for encoding. - */ - void encode(byte[] in, int inPos, int inAvail) { - if (eof) { - return; - } - - // inAvail < 0 is how we're informed of EOF in the underlying data we're - // encoding. - if (inAvail < 0) { - eof = true; - if (buf == null || buf.length - pos < encodeSize) { - resizeBuf(); - } - switch (modulus) { - case 1: - buf[pos++] = intToBase64[(x >> 2) & MASK_6BITS]; - buf[pos++] = intToBase64[(x << 4) & MASK_6BITS]; - buf[pos++] = PAD; - buf[pos++] = PAD; - break; - - case 2: - buf[pos++] = intToBase64[(x >> 10) & MASK_6BITS]; - buf[pos++] = intToBase64[(x >> 4) & MASK_6BITS]; - buf[pos++] = intToBase64[(x << 2) & MASK_6BITS]; - buf[pos++] = PAD; - break; - } - if (lineLength > 0) { - System.arraycopy(lineSeparator, 0, buf, pos, lineSeparator.length); - pos += lineSeparator.length; - } - } else { - for (int i = 0; i < inAvail; i++) { - if (buf == null || buf.length - pos < encodeSize) { - resizeBuf(); - } - modulus = (++modulus) % 3; - int b = in[inPos++]; - if (b < 0) { b += 256; } - x = (x << 8) + b; - if (0 == modulus) { - buf[pos++] = intToBase64[(x >> 18) & MASK_6BITS]; - buf[pos++] = intToBase64[(x >> 12) & MASK_6BITS]; - buf[pos++] = intToBase64[(x >> 6) & MASK_6BITS]; - buf[pos++] = intToBase64[x & MASK_6BITS]; - currentLinePos += 4; - if (lineLength > 0 && lineLength <= currentLinePos) { - System.arraycopy(lineSeparator, 0, buf, pos, lineSeparator.length); - pos += lineSeparator.length; - currentLinePos = 0; - } - } - } - } - } - - /** - *

- * Decodes all of the provided data, starting at inPos, for inAvail bytes. - * Should be called at least twice: once with the data to decode, and once - * with inAvail set to "-1" to alert decoder that EOF has been reached. - * The "-1" call is not necessary when decoding, but it doesn't hurt, either. - *

- * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) - * data is handled, since CR and LF are silently ignored, but has implications - * for other bytes, too. This method subscribes to the garbage-in, garbage-out - * philosophy: it will not check the provided data for validity. - *

- * Thanks to "commons" project in ws.apache.org for the bitwise operations, - * and general approach. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - *

- - * @param in byte[] array of ascii data to base64 decode. - * @param inPos Position to start reading data from. - * @param inAvail Amount of bytes available from input for encoding. - */ - void decode(byte[] in, int inPos, int inAvail) { - if (eof) { - return; - } - if (inAvail < 0) { - eof = true; - } - for (int i = 0; i < inAvail; i++) { - if (buf == null || buf.length - pos < decodeSize) { - resizeBuf(); - } - byte b = in[inPos++]; - if (b == PAD) { - x = x << 6; - switch (modulus) { - case 2: - x = x << 6; - buf[pos++] = (byte) ((x >> 16) & MASK_8BITS); - break; - case 3: - buf[pos++] = (byte) ((x >> 16) & MASK_8BITS); - buf[pos++] = (byte) ((x >> 8) & MASK_8BITS); - break; - } - // WE'RE DONE!!!! - eof = true; - return; - } else { - if (b >= 0 && b < base64ToInt.length) { - int result = base64ToInt[b]; - if (result >= 0) { - modulus = (++modulus) % 4; - x = (x << 6) + result; - if (modulus == 0) { - buf[pos++] = (byte) ((x >> 16) & MASK_8BITS); - buf[pos++] = (byte) ((x >> 8) & MASK_8BITS); - buf[pos++] = (byte) (x & MASK_8BITS); - } - } - } - } - } - } - - /** - * Returns whether or not the octet is in the base 64 alphabet. - * - * @param octet - * The value to test - * @return true if the value is defined in the the base 64 alphabet, false otherwise. - */ - public static boolean isBase64(byte octet) { - return octet == PAD || (octet >= 0 && octet < base64ToInt.length && base64ToInt[octet] != -1); - } - - /** - * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. - * Currently the method treats whitespace as valid. - * - * @param arrayOctet - * byte array to test - * @return true if all bytes are valid characters in the Base64 alphabet or if the byte array is - * empty; false, otherwise - */ - public static boolean isArrayByteBase64(byte[] arrayOctet) { - for (int i = 0; i < arrayOctet.length; i++) { - if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) { - return false; - } - } - return true; - } - - /* - * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. - * - * @param arrayOctet - * byte array to test - * @return true if any byte is a valid character in the Base64 alphabet; false herwise - */ - private static boolean containsBase64Byte(byte[] arrayOctet) { - for (int i = 0; i < arrayOctet.length; i++) { - if (isBase64(arrayOctet[i])) { - return true; - } - } - return false; - } - - /** - * Encodes binary data using the base64 algorithm but does not chunk the output. - * - * @param binaryData - * binary data to encode - * @return Base64 characters - */ - public static byte[] encodeBase64(byte[] binaryData) { - return encodeBase64(binaryData, false); - } - - /** - * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks - * - * @param binaryData - * binary data to encode - * @return Base64 characters chunked in 76 character blocks - */ - public static byte[] encodeBase64Chunked(byte[] binaryData) { - return encodeBase64(binaryData, true); - } - - /** - * Decodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the - * Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[]. - * - * @param pObject - * Object to decode - * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] supplied. - * @throws DecoderException - * if the parameter supplied is not of type byte[] - */ - public Object decode(Object pObject) throws DecoderException { - if (!(pObject instanceof byte[])) { - throw new DecoderException("Parameter supplied to Base64 decode is not a byte[]"); - } - return decode((byte[]) pObject); - } - - /** - * Decodes a byte[] containing containing characters in the Base64 alphabet. - * - * @param pArray - * A byte array containing Base64 character data - * @return a byte array containing binary data - */ - public byte[] decode(byte[] pArray) { - return decodeBase64(pArray); - } - - /** - * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. - * - * @param binaryData - * Array containing binary data to encode. - * @param isChunked - * if true this encoder will chunk the base64 output into 76 character blocks - * @return Base64-encoded data. - * @throws IllegalArgumentException - * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} - */ - public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { - if (binaryData == null || binaryData.length == 0) { - return binaryData; - } - Base64 b64 = isChunked ? new Base64() : new Base64(0); - - long len = (binaryData.length * 4) / 3; - long mod = len % 4; - if (mod != 0) { - len += 4 - mod; - } - if (isChunked) { - len += (1 + (len / CHUNK_SIZE)) * CHUNK_SEPARATOR.length; - } - - if (len > Integer.MAX_VALUE) { - throw new IllegalArgumentException( - "Input array too big, output array would be bigger than Integer.MAX_VALUE=" + Integer.MAX_VALUE); - } - byte[] buf = new byte[(int) len]; - b64.setInitialBuffer(buf, 0, buf.length); - b64.encode(binaryData, 0, binaryData.length); - b64.encode(binaryData, 0, -1); // Notify encoder of EOF. - - // Encoder might have resized, even though it was unnecessary. - if (b64.buf != buf) { - b64.readResults(buf, 0, buf.length); - } - return buf; - } - - /** - * Decodes Base64 data into octets - * - * @param base64Data Byte array containing Base64 data - * @return Array containing decoded data. - */ - public static byte[] decodeBase64(byte[] base64Data) { - if (base64Data == null || base64Data.length == 0) { - return base64Data; - } - Base64 b64 = new Base64(); - - long len = (base64Data.length * 3) / 4; - byte[] buf = new byte[(int) len]; - b64.setInitialBuffer(buf, 0, buf.length); - b64.decode(base64Data, 0, base64Data.length); - b64.decode(base64Data, 0, -1); // Notify decoder of EOF. - - // We have no idea what the line-length was, so we - // cannot know how much of our array wasn't used. - byte[] result = new byte[b64.pos]; - b64.readResults(result, 0, result.length); - return result; - } - - /** - * Discards any whitespace from a base-64 encoded block. - * - * @param data - * The base-64 encoded data to discard the whitespace from. - * @return The data, less whitespace (see RFC 2045). - * @deprecated This method is no longer needed - */ - static byte[] discardWhitespace(byte[] data) { - byte groomedData[] = new byte[data.length]; - int bytesCopied = 0; - - for (int i = 0; i < data.length; i++) { - switch (data[i]) { - case ' ' : - case '\n' : - case '\r' : - case '\t' : - break; - default : - groomedData[bytesCopied++] = data[i]; - } - } - - byte packedData[] = new byte[bytesCopied]; - - System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); - - return packedData; - } - - - /** - * Check if a byte value is whitespace or not. - * - * @param byteToCheck the byte to check - * @return true if byte is whitespace, false otherwise - */ - private static boolean isWhiteSpace(byte byteToCheck){ - switch (byteToCheck) { - case ' ' : - case '\n' : - case '\r' : - case '\t' : - return true; - default : - return false; - } - } - - /** - * Discards any characters outside of the base64 alphabet, per the requirements on page 25 of RFC 2045 - "Any - * characters outside of the base64 alphabet are to be ignored in base64 encoded data." - * - * @param data - * The base-64 encoded data to groom - * @return The data, less non-base64 characters (see RFC 2045). - */ - static byte[] discardNonBase64(byte[] data) { - byte groomedData[] = new byte[data.length]; - int bytesCopied = 0; - - for (int i = 0; i < data.length; i++) { - if (isBase64(data[i])) { - groomedData[bytesCopied++] = data[i]; - } - } - - byte packedData[] = new byte[bytesCopied]; - - System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); - - return packedData; - } - - // Implementation of the Encoder Interface - - /** - * Encodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the - * Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[]. - * - * @param pObject - * Object to encode - * @return An object (of type byte[]) containing the base64 encoded data which corresponds to the byte[] supplied. - * @throws EncoderException - * if the parameter supplied is not of type byte[] - */ - public Object encode(Object pObject) throws EncoderException { - if (!(pObject instanceof byte[])) { - throw new EncoderException("Parameter supplied to Base64 encode is not a byte[]"); - } - return encode((byte[]) pObject); - } - - /** - * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet. - * - * @param pArray - * a byte array containing binary data - * @return A byte array containing only Base64 character data - */ - public byte[] encode(byte[] pArray) { - return encodeBase64(pArray, false); - } - - // Implementation of integer encoding used for crypto - /** - * Decode a byte64-encoded integer according to crypto - * standards such as W3C's XML-Signature - * - * @param pArray a byte array containing base64 character data - * @return A BigInteger - */ - public static BigInteger decodeInteger(byte[] pArray) { - return new BigInteger(1, decodeBase64(pArray)); - } - - /** - * Encode to a byte64-encoded integer according to crypto - * standards such as W3C's XML-Signature - * - * @param bigInt a BigInteger - * @return A byte array containing base64 character data - * @throws NullPointerException if null is passed in - */ - public static byte[] encodeInteger(BigInteger bigInt) { - if(bigInt == null) { - throw new NullPointerException("encodeInteger called with null parameter"); - } - - return encodeBase64(toIntegerBytes(bigInt), false); - } - - /** - * Returns a byte-array representation of a BigInteger - * without sign bit. - * - * @param bigInt BigInteger to be converted - * @return a byte array representation of the BigInteger parameter - */ - static byte[] toIntegerBytes(BigInteger bigInt) { - int bitlen = bigInt.bitLength(); - // round bitlen - bitlen = ((bitlen + 7) >> 3) << 3; - byte[] bigBytes = bigInt.toByteArray(); - - if(((bigInt.bitLength() % 8) != 0) && - (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { - return bigBytes; - } - - // set up params for copying everything but sign bit - int startSrc = 0; - int len = bigBytes.length; - - // if bigInt is exactly byte-aligned, just skip signbit in copy - if((bigInt.bitLength() % 8) == 0) { - startSrc = 1; - len--; - } - - int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec - byte[] resizedBytes = new byte[bitlen / 8]; - - System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); - - return resizedBytes; - } -} diff --git a/src/com/fsck/k9/codec/binary/Base64OutputStream.java b/src/com/fsck/k9/codec/binary/Base64OutputStream.java deleted file mode 100644 index f812cd368..000000000 --- a/src/com/fsck/k9/codec/binary/Base64OutputStream.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.fsck.k9.codec.binary; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Provides Base64 encoding and decoding in a streaming fashion (unlimited size). - * When encoding the default lineLength is 76 characters and the default - * lineEnding is CRLF, but these can be overridden by using the appropriate - * constructor. - *

- * The default behaviour of the Base64OutputStream is to ENCODE, whereas the - * default behaviour of the Base64InputStream is to DECODE. But this behaviour - * can be overridden by using a different constructor. - *

- * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose - * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein. - *

- * - * @author Apache Software Foundation - * @version $Id $ - * @see RFC 2045 - * @since 1.0-dev - */ -public class Base64OutputStream extends FilterOutputStream { - private final boolean doEncode; - private final Base64 base64; - private final byte[] singleByte = new byte[1]; - - /** - * Creates a Base64OutputStream such that all data written is Base64-encoded - * to the original provided OutputStream. - * - * @param out OutputStream to wrap. - */ - public Base64OutputStream(OutputStream out) { - this(out, true); - } - - /** - * Creates a Base64OutputStream such that all data written is either - * Base64-encoded or Base64-decoded to the original provided OutputStream. - * - * @param out OutputStream to wrap. - * @param doEncode true if we should encode all data written to us, - * false if we should decode. - */ - public Base64OutputStream(OutputStream out, boolean doEncode) { - super(out); - this.doEncode = doEncode; - this.base64 = new Base64(); - } - - /** - * Creates a Base64OutputStream such that all data written is either - * Base64-encoded or Base64-decoded to the original provided OutputStream. - * - * @param out OutputStream to wrap. - * @param doEncode true if we should encode all data written to us, - * false if we should decode. - * @param lineLength If doEncode is true, each line of encoded - * data will contain lineLength characters. - * If lineLength <=0, the encoded data is not divided into lines. - * If doEncode is false, lineLength is ignored. - * @param lineSeparator If doEncode is true, each line of encoded - * data will be terminated with this byte sequence (e.g. \r\n). - * If lineLength <= 0, the lineSeparator is not used. - * If doEncode is false lineSeparator is ignored. - */ - public Base64OutputStream(OutputStream out, boolean doEncode, int lineLength, byte[] lineSeparator) { - super(out); - this.doEncode = doEncode; - this.base64 = new Base64(lineLength, lineSeparator); - } - - /** - * Writes the specified byte to this output stream. - */ - public void write(int i) throws IOException { - singleByte[0] = (byte) i; - write(singleByte, 0, 1); - } - - /** - * Writes len bytes from the specified - * b array starting at offset to - * this output stream. - * - * @param b source byte array - * @param offset where to start reading the bytes - * @param len maximum number of bytes to write - * - * @throws IOException if an I/O error occurs. - * @throws NullPointerException if the byte array parameter is null - * @throws IndexOutOfBoundsException if offset, len or buffer size are invalid - */ - public void write(byte b[], int offset, int len) throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if (offset < 0 || len < 0 || offset + len < 0) { - throw new IndexOutOfBoundsException(); - } else if (offset > b.length || offset + len > b.length) { - throw new IndexOutOfBoundsException(); - } else if (len > 0) { - if (doEncode) { - base64.encode(b, offset, len); - } else { - base64.decode(b, offset, len); - } - flush(false); - } - } - - /** - * Flushes this output stream and forces any buffered output bytes - * to be written out to the stream. If propogate is true, the wrapped - * stream will also be flushed. - * - * @param propogate boolean flag to indicate whether the wrapped - * OutputStream should also be flushed. - * @throws IOException if an I/O error occurs. - */ - private void flush(boolean propogate) throws IOException { - int avail = base64.avail(); - if (avail > 0) { - byte[] buf = new byte[avail]; - int c = base64.readResults(buf, 0, avail); - if (c > 0) { - out.write(buf, 0, c); - } - } - if (propogate) { - out.flush(); - } - } - - /** - * Flushes this output stream and forces any buffered output bytes - * to be written out to the stream. - * - * @throws IOException if an I/O error occurs. - */ - public void flush() throws IOException { - flush(true); - } - - /** - * Closes this output stream, flushing any remaining bytes that must be encoded. The - * underlying stream is flushed but not closed. - */ - public void close() throws IOException { - // Notify encoder of EOF (-1). - if (doEncode) { - base64.encode(singleByte, 0, -1); - } else { - base64.decode(singleByte, 0, -1); - } - flush(); - } - -} diff --git a/src/com/fsck/k9/k9.java b/src/com/fsck/k9/k9.java deleted file mode 100644 index d53e42490..000000000 --- a/src/com/fsck/k9/k9.java +++ /dev/null @@ -1,169 +0,0 @@ - -package com.fsck.k9; - -import java.io.File; - -import android.app.Application; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.activity.MessageCompose; -import com.fsck.k9.mail.internet.BinaryTempFileBody; -import com.fsck.k9.mail.internet.MimeMessage; -import com.fsck.k9.service.BootReceiver; -import com.fsck.k9.service.MailService; - -public class k9 extends Application { - public static final String LOG_TAG = "k9"; - - public static File tempDirectory; - - /** - * If this is enabled there will be additional logging information sent to - * Log.d, including protocol dumps. - */ - public static boolean DEBUG = false; - - /** - * If this is enabled than logging that normally hides sensitive information - * like passwords will show that information. - */ - public static boolean DEBUG_SENSITIVE = false; - - - /** - * The MIME type(s) of attachments we're willing to send. At the moment it is not possible - * to open a chooser with a list of filter types, so the chooser is only opened with the first - * item in the list. The entire list will be used to filter down attachments that are added - * with Intent.ACTION_SEND. - */ - public static final String[] ACCEPTABLE_ATTACHMENT_SEND_TYPES = new String[] { - "image/*", - }; - - /** - * The MIME type(s) of attachments we're willing to view. - */ - public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] { - "image/*", - "audio/*", - "text/*", - }; - - /** - * The MIME type(s) of attachments we're not willing to view. - */ - public static final String[] UNACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] { - "image/gif", - }; - - /** - * The MIME type(s) of attachments we're willing to download to SD. - */ - public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] { - "image/*", - }; - - /** - * The MIME type(s) of attachments we're not willing to download to SD. - */ - public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] { - "image/gif", - }; - - /** - * The special name "INBOX" is used throughout the application to mean "Whatever folder - * the server refers to as the user's Inbox. Placed here to ease use. - */ - public static final String INBOX = "INBOX"; - - /** - * Specifies how many messages will be shown in a folder by default. This number is set - * on each new folder and can be incremented with "Load more messages..." by the - * VISIBLE_LIMIT_INCREMENT - */ - public static final int DEFAULT_VISIBLE_LIMIT = 25; - - /** - * Number of additional messages to load when a user selectes "Load more messages..." - */ - public static final int VISIBLE_LIMIT_INCREMENT = 25; - - /** - * The maximum size of an attachment we're willing to download (either View or Save) - * Attachments that are base64 encoded (most) will be about 1.375x their actual size - * so we should probably factor that in. A 5MB attachment will generally be around - * 6.8MB downloaded but only 5MB saved. - */ - public static final int MAX_ATTACHMENT_DOWNLOAD_SIZE = (5 * 1024 * 1024); - - /** - * Called throughout the application when the number of accounts has changed. This method - * enables or disables the Compose activity, the boot receiver and the service based on - * whether any accounts are configured. - */ - public static void setServicesEnabled(Context context) { - setServicesEnabled(context, Preferences.getPreferences(context).getAccounts().length > 0); - } - - public static void setServicesEnabled(Context context, boolean enabled) { - PackageManager pm = context.getPackageManager(); - if (!enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) == - PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { - /* - * If no accounts now exist but the service is still enabled we're about to disable it - * so we'll reschedule to kill off any existing alarms. - */ - MailService.actionReschedule(context); - } - pm.setComponentEnabledSetting( - new ComponentName(context, MessageCompose.class), - enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - pm.setComponentEnabledSetting( - new ComponentName(context, BootReceiver.class), - enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - pm.setComponentEnabledSetting( - new ComponentName(context, MailService.class), - enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - if (enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) == - PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { - /* - * And now if accounts do exist then we've just enabled the service and we want to - * schedule alarms for the new accounts. - */ - MailService.actionReschedule(context); - } - } - - @Override - public void onCreate() { - super.onCreate(); - Preferences prefs = Preferences.getPreferences(this); - DEBUG = prefs.geteEnableDebugLogging(); - DEBUG_SENSITIVE = prefs.getEnableSensitiveLogging(); - MessagingController.getInstance(this).resetVisibleLimits(prefs.getAccounts()); - - /* - * We have to give MimeMessage a temp directory because File.createTempFile(String, String) - * doesn't work in Android and MimeMessage does not have access to a Context. - */ - BinaryTempFileBody.setTempDirectory(getCacheDir()); - } -} - - - - - - - - diff --git a/src/com/fsck/k9/mail/Address.java b/src/com/fsck/k9/mail/Address.java deleted file mode 100644 index 9b64631d8..000000000 --- a/src/com/fsck/k9/mail/Address.java +++ /dev/null @@ -1,215 +0,0 @@ - -package com.fsck.k9.mail; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.james.mime4j.field.address.AddressList; -import org.apache.james.mime4j.field.address.Mailbox; -import org.apache.james.mime4j.field.address.MailboxList; -import org.apache.james.mime4j.field.address.NamedMailbox; -import org.apache.james.mime4j.field.address.parser.ParseException; - -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.Utility; -import com.fsck.k9.mail.internet.MimeUtility; - -public class Address { - String mAddress; - - String mPersonal; - - public Address(String address, String personal) { - this.mAddress = address; - this.mPersonal = personal; - } - - public Address(String address) { - this.mAddress = address; - } - - public String getAddress() { - return mAddress; - } - - public void setAddress(String address) { - this.mAddress = address; - } - - public String getPersonal() { - return mPersonal; - } - - public void setPersonal(String personal) { - this.mPersonal = personal; - } - - /** - * Parse a comma separated list of addresses in RFC-822 format and return an - * array of Address objects. - * - * @param addressList - * @return An array of 0 or more Addresses. - */ - public static Address[] parse(String addressList) { - ArrayList
addresses = new ArrayList
(); - if (addressList == null) { - return new Address[] {}; - } - try { - MailboxList parsedList = AddressList.parse(addressList).flatten(); - for (int i = 0, count = parsedList.size(); i < count; i++) { - org.apache.james.mime4j.field.address.Address address = parsedList.get(i); - if (address instanceof NamedMailbox) { - NamedMailbox namedMailbox = (NamedMailbox)address; - addresses.add(new Address(namedMailbox.getLocalPart() + "@" - + namedMailbox.getDomain(), namedMailbox.getName())); - } else if (address instanceof Mailbox) { - Mailbox mailbox = (Mailbox)address; - addresses.add(new Address(mailbox.getLocalPart() + "@" + mailbox.getDomain())); - } else { - Log.e(k9.LOG_TAG, "Unknown address type from Mime4J: " - + address.getClass().toString()); - } - - } - } catch (ParseException pe) { - } - return addresses.toArray(new Address[] {}); - } - - @Override - public boolean equals(Object o) { - if (o instanceof Address) { - return getAddress().equals(((Address) o).getAddress()); - } - return super.equals(o); - } - - public String toString() { - if (mPersonal != null) { - if (mPersonal.matches(".*[\\(\\)<>@,;:\\\\\".\\[\\]].*")) { - return Utility.quoteString(mPersonal) + " <" + mAddress + ">"; - } else { - return mPersonal + " <" + mAddress + ">"; - } - } else { - return mAddress; - } - } - - public static String toString(Address[] addresses) { - if (addresses == null) { - return null; - } - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < addresses.length; i++) { - sb.append(addresses[i].toString()); - if (i < addresses.length - 1) { - sb.append(','); - } - } - return sb.toString(); - } - - /** - * Returns either the personal portion of the Address or the address portion if the personal - * is not available. - * @return - */ - public String toFriendly() { - if (mPersonal != null && mPersonal.length() > 0) { - return mPersonal; - } - else { - return mAddress; - } - } - - public static String toFriendly(Address[] addresses) { - if (addresses == null) { - return null; - } - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < addresses.length; i++) { - sb.append(addresses[i].toFriendly()); - if (i < addresses.length - 1) { - sb.append(','); - } - } - return sb.toString(); - } - - /** - * Unpacks an address list previously packed with packAddressList() - * @param list - * @return - */ - public static Address[] unpack(String addressList) { - if (addressList == null) { - return new Address[] { }; - } - ArrayList
addresses = new ArrayList
(); - int length = addressList.length(); - int pairStartIndex = 0; - int pairEndIndex = 0; - int addressEndIndex = 0; - while (pairStartIndex < length) { - pairEndIndex = addressList.indexOf(',', pairStartIndex); - if (pairEndIndex == -1) { - pairEndIndex = length; - } - addressEndIndex = addressList.indexOf(';', pairStartIndex); - String address = null; - String personal = null; - if (addressEndIndex == -1 || addressEndIndex > pairEndIndex) { - address = Utility.fastUrlDecode(addressList.substring(pairStartIndex, pairEndIndex)); - } - else { - address = Utility.fastUrlDecode(addressList.substring(pairStartIndex, addressEndIndex)); - personal = Utility.fastUrlDecode(addressList.substring(addressEndIndex + 1, pairEndIndex)); - } - addresses.add(new Address(address, personal)); - pairStartIndex = pairEndIndex + 1; - } - return addresses.toArray(new Address[] { }); - } - - /** - * Packs an address list into a String that is very quick to read - * and parse. Packed lists can be unpacked with unpackAddressList() - * The packed list is a comma seperated list of: - * URLENCODE(address)[;URLENCODE(personal)] - * @param list - * @return - */ - public static String pack(Address[] addresses) { - if (addresses == null) { - return null; - } - StringBuffer sb = new StringBuffer(); - for (int i = 0, count = addresses.length; i < count; i++) { - Address address = addresses[i]; - try { - sb.append(URLEncoder.encode(address.getAddress(), "UTF-8")); - if (address.getPersonal() != null) { - sb.append(';'); - sb.append(URLEncoder.encode(address.getPersonal(), "UTF-8")); - } - if (i < count - 1) { - sb.append(','); - } - } - catch (UnsupportedEncodingException uee) { - return null; - } - } - return sb.toString(); - } -} diff --git a/src/com/fsck/k9/mail/AuthenticationFailedException.java b/src/com/fsck/k9/mail/AuthenticationFailedException.java deleted file mode 100644 index 006063a14..000000000 --- a/src/com/fsck/k9/mail/AuthenticationFailedException.java +++ /dev/null @@ -1,14 +0,0 @@ - -package com.fsck.k9.mail; - -public class AuthenticationFailedException extends MessagingException { - public static final long serialVersionUID = -1; - - public AuthenticationFailedException(String message) { - super(message); - } - - public AuthenticationFailedException(String message, Throwable throwable) { - super(message, throwable); - } -} diff --git a/src/com/fsck/k9/mail/Body.java b/src/com/fsck/k9/mail/Body.java deleted file mode 100644 index 7deb2a1eb..000000000 --- a/src/com/fsck/k9/mail/Body.java +++ /dev/null @@ -1,11 +0,0 @@ - -package com.fsck.k9.mail; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public interface Body { - public InputStream getInputStream() throws MessagingException; - public void writeTo(OutputStream out) throws IOException, MessagingException; -} diff --git a/src/com/fsck/k9/mail/BodyPart.java b/src/com/fsck/k9/mail/BodyPart.java deleted file mode 100644 index e5f9375e6..000000000 --- a/src/com/fsck/k9/mail/BodyPart.java +++ /dev/null @@ -1,10 +0,0 @@ - -package com.fsck.k9.mail; - -public abstract class BodyPart implements Part { - protected Multipart mParent; - - public Multipart getParent() { - return mParent; - } -} diff --git a/src/com/fsck/k9/mail/CertificateValidationException.java b/src/com/fsck/k9/mail/CertificateValidationException.java deleted file mode 100644 index ed35cf8ac..000000000 --- a/src/com/fsck/k9/mail/CertificateValidationException.java +++ /dev/null @@ -1,14 +0,0 @@ - -package com.fsck.k9.mail; - -public class CertificateValidationException extends MessagingException { - public static final long serialVersionUID = -1; - - public CertificateValidationException(String message) { - super(message); - } - - public CertificateValidationException(String message, Throwable throwable) { - super(message, throwable); - } -} \ No newline at end of file diff --git a/src/com/fsck/k9/mail/FetchProfile.java b/src/com/fsck/k9/mail/FetchProfile.java deleted file mode 100644 index 95bc44712..000000000 --- a/src/com/fsck/k9/mail/FetchProfile.java +++ /dev/null @@ -1,57 +0,0 @@ - -package com.fsck.k9.mail; - -import java.util.ArrayList; - -/** - *
- * A FetchProfile is a list of items that should be downloaded in bulk for a set of messages.
- * FetchProfile can contain the following objects:
- *      FetchProfile.Item:      Described below.
- *      Message:                Indicates that the body of the entire message should be fetched.
- *                              Synonymous with FetchProfile.Item.BODY.
- *      Part:                   Indicates that the given Part should be fetched. The provider
- *                              is expected have previously created the given BodyPart and stored
- *                              any information it needs to download the content.
- * 
- */ -public class FetchProfile extends ArrayList { - /** - * Default items available for pre-fetching. It should be expected that any - * item fetched by using these items could potentially include all of the - * previous items. - */ - public enum Item { - /** - * Download the flags of the message. - */ - FLAGS, - - /** - * Download the envelope of the message. This should include at minimum - * the size and the following headers: date, subject, from, content-type, to, cc - */ - ENVELOPE, - - /** - * Download the structure of the message. This maps directly to IMAP's BODYSTRUCTURE - * and may map to other providers. - * The provider should, if possible, fill in a properly formatted MIME structure in - * the message without actually downloading any message data. If the provider is not - * capable of this operation it should specifically set the body of the message to null - * so that upper levels can detect that a full body download is needed. - */ - STRUCTURE, - - /** - * A sane portion of the entire message, cut off at a provider determined limit. - * This should generaly be around 50kB. - */ - BODY_SANE, - - /** - * The entire message. - */ - BODY, - } -} diff --git a/src/com/fsck/k9/mail/Flag.java b/src/com/fsck/k9/mail/Flag.java deleted file mode 100644 index ec898a700..000000000 --- a/src/com/fsck/k9/mail/Flag.java +++ /dev/null @@ -1,48 +0,0 @@ - -package com.fsck.k9.mail; - -/** - * Flags that can be applied to Messages. - */ -public enum Flag { - DELETED, - SEEN, - ANSWERED, - FLAGGED, - DRAFT, - RECENT, - - /* - * The following flags are for internal library use only. - * TODO Eventually we should creates a Flags class that extends ArrayList that allows - * these flags and Strings to represent user defined flags. At that point the below - * flags should become user defined flags. - */ - /** - * Delete and remove from the LocalStore immediately. - */ - X_DESTROYED, - - /** - * Sending of an unsent message failed. It will be retried. Used to show status. - */ - X_SEND_FAILED, - - /** - * Sending of an unsent message is in progress. - */ - X_SEND_IN_PROGRESS, - - /** - * Indicates that a message is fully downloaded from the server and can be viewed normally. - * This does not include attachments, which are never downloaded fully. - */ - X_DOWNLOADED_FULL, - - /** - * Indicates that a message is partially downloaded from the server and can be viewed but - * more content is available on the server. - * This does not include attachments, which are never downloaded fully. - */ - X_DOWNLOADED_PARTIAL, -} diff --git a/src/com/fsck/k9/mail/Folder.java b/src/com/fsck/k9/mail/Folder.java deleted file mode 100644 index 2f951e336..000000000 --- a/src/com/fsck/k9/mail/Folder.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.fsck.k9.mail; - - -public abstract class Folder { - public enum OpenMode { - READ_WRITE, READ_ONLY, - } - - public enum FolderType { - HOLDS_FOLDERS, HOLDS_MESSAGES, - } - - /** - * Forces an open of the MailProvider. If the provider is already open this - * function returns without doing anything. - * - * @param mode READ_ONLY or READ_WRITE - */ - public abstract void open(OpenMode mode) throws MessagingException; - - /** - * Forces a close of the MailProvider. Any further access will attempt to - * reopen the MailProvider. - * - * @param expunge If true all deleted messages will be expunged. - */ - public abstract void close(boolean expunge) throws MessagingException; - - /** - * @return True if further commands are not expected to have to open the - * connection. - */ - public abstract boolean isOpen(); - - /** - * Get the mode the folder was opened with. This may be different than the mode the open - * was requested with. - * @return - */ - public abstract OpenMode getMode() throws MessagingException; - - public abstract boolean create(FolderType type) throws MessagingException; - - public abstract boolean exists() throws MessagingException; - - /** - * @return A count of the messages in the selected folder. - */ - public abstract int getMessageCount() throws MessagingException; - - public abstract int getUnreadMessageCount() throws MessagingException; - - public abstract Message getMessage(String uid) throws MessagingException; - - public abstract Message[] getMessages(int start, int end, MessageRetrievalListener listener) - throws MessagingException; - - /** - * Fetches the given list of messages. The specified listener is notified as - * each fetch completes. Messages are downloaded as (as) lightweight (as - * possible) objects to be filled in with later requests. In most cases this - * means that only the UID is downloaded. - * - * @param uids - * @param listener - */ - public abstract Message[] getMessages(MessageRetrievalListener listener) - throws MessagingException; - - public abstract Message[] getMessages(String[] uids, MessageRetrievalListener listener) - throws MessagingException; - - public abstract void appendMessages(Message[] messages) throws MessagingException; - - public abstract void copyMessages(Message[] msgs, Folder folder) throws MessagingException; - - public abstract void setFlags(Message[] messages, Flag[] flags, boolean value) - throws MessagingException; - - public abstract Message[] expunge() throws MessagingException; - - public abstract void fetch(Message[] messages, FetchProfile fp, - MessageRetrievalListener listener) throws MessagingException; - - public abstract void delete(boolean recurse) throws MessagingException; - - public abstract String getName(); - - public abstract Flag[] getPermanentFlags() throws MessagingException; - - @Override - public String toString() { - return getName(); - } -} diff --git a/src/com/fsck/k9/mail/Message.java b/src/com/fsck/k9/mail/Message.java deleted file mode 100644 index 58f036304..000000000 --- a/src/com/fsck/k9/mail/Message.java +++ /dev/null @@ -1,118 +0,0 @@ - -package com.fsck.k9.mail; - -import java.util.Date; -import java.util.HashSet; - -public abstract class Message implements Part, Body { - public enum RecipientType { - TO, CC, BCC, - } - - protected String mUid; - - protected HashSet mFlags = new HashSet(); - - protected Date mInternalDate; - - protected Folder mFolder; - - public String getUid() { - return mUid; - } - - public void setUid(String uid) { - this.mUid = uid; - } - - public Folder getFolder() { - return mFolder; - } - - public abstract String getSubject() throws MessagingException; - - public abstract void setSubject(String subject) throws MessagingException; - - public Date getInternalDate() { - return mInternalDate; - } - - public void setInternalDate(Date internalDate) { - this.mInternalDate = internalDate; - } - - public abstract Date getReceivedDate() throws MessagingException; - - public abstract Date getSentDate() throws MessagingException; - - public abstract void setSentDate(Date sentDate) throws MessagingException; - - public abstract Address[] getRecipients(RecipientType type) throws MessagingException; - - public abstract void setRecipients(RecipientType type, Address[] addresses) - throws MessagingException; - - public void setRecipient(RecipientType type, Address address) throws MessagingException { - setRecipients(type, new Address[] { - address - }); - } - - public abstract Address[] getFrom() throws MessagingException; - - public abstract void setFrom(Address from) throws MessagingException; - - public abstract Address[] getReplyTo() throws MessagingException; - - public abstract void setReplyTo(Address[] from) throws MessagingException; - - public abstract Body getBody() throws MessagingException; - - public abstract String getContentType() throws MessagingException; - - public abstract void addHeader(String name, String value) throws MessagingException; - - public abstract void setHeader(String name, String value) throws MessagingException; - - public abstract String[] getHeader(String name) throws MessagingException; - - public abstract void removeHeader(String name) throws MessagingException; - - public abstract void setBody(Body body) throws MessagingException; - - public boolean isMimeType(String mimeType) throws MessagingException { - return getContentType().startsWith(mimeType); - } - - /* - * TODO Refactor Flags at some point to be able to store user defined flags. - */ - public Flag[] getFlags() { - return mFlags.toArray(new Flag[] {}); - } - - public void setFlag(Flag flag, boolean set) throws MessagingException { - if (set) { - mFlags.add(flag); - } else { - mFlags.remove(flag); - } - } - - /** - * This method calls setFlag(Flag, boolean) - * @param flags - * @param set - */ - public void setFlags(Flag[] flags, boolean set) throws MessagingException { - for (Flag flag : flags) { - setFlag(flag, set); - } - } - - public boolean isSet(Flag flag) { - return mFlags.contains(flag); - } - - public abstract void saveChanges() throws MessagingException; -} diff --git a/src/com/fsck/k9/mail/MessageDateComparator.java b/src/com/fsck/k9/mail/MessageDateComparator.java deleted file mode 100644 index 2bde7af0b..000000000 --- a/src/com/fsck/k9/mail/MessageDateComparator.java +++ /dev/null @@ -1,19 +0,0 @@ - -package com.fsck.k9.mail; - -import java.util.Comparator; - -public class MessageDateComparator implements Comparator { - public int compare(Message o1, Message o2) { - try { - if (o1.getSentDate() == null) { - return 1; - } else if (o2.getSentDate() == null) { - return -1; - } else - return o2.getSentDate().compareTo(o1.getSentDate()); - } catch (Exception e) { - return 0; - } - } -} diff --git a/src/com/fsck/k9/mail/MessageRetrievalListener.java b/src/com/fsck/k9/mail/MessageRetrievalListener.java deleted file mode 100644 index 2a1446211..000000000 --- a/src/com/fsck/k9/mail/MessageRetrievalListener.java +++ /dev/null @@ -1,8 +0,0 @@ - -package com.fsck.k9.mail; - -public interface MessageRetrievalListener { - public void messageStarted(String uid, int number, int ofTotal); - - public void messageFinished(Message message, int number, int ofTotal); -} diff --git a/src/com/fsck/k9/mail/MessagingException.java b/src/com/fsck/k9/mail/MessagingException.java deleted file mode 100644 index 7e0a0d263..000000000 --- a/src/com/fsck/k9/mail/MessagingException.java +++ /dev/null @@ -1,14 +0,0 @@ - -package com.fsck.k9.mail; - -public class MessagingException extends Exception { - public static final long serialVersionUID = -1; - - public MessagingException(String message) { - super(message); - } - - public MessagingException(String message, Throwable throwable) { - super(message, throwable); - } -} diff --git a/src/com/fsck/k9/mail/Multipart.java b/src/com/fsck/k9/mail/Multipart.java deleted file mode 100644 index 787f5b382..000000000 --- a/src/com/fsck/k9/mail/Multipart.java +++ /dev/null @@ -1,48 +0,0 @@ - -package com.fsck.k9.mail; - -import java.util.ArrayList; - -public abstract class Multipart implements Body { - protected Part mParent; - - protected ArrayList mParts = new ArrayList(); - - protected String mContentType; - - public void addBodyPart(BodyPart part) throws MessagingException { - mParts.add(part); - } - - public void addBodyPart(BodyPart part, int index) throws MessagingException { - mParts.add(index, part); - } - - public BodyPart getBodyPart(int index) throws MessagingException { - return mParts.get(index); - } - - public String getContentType() throws MessagingException { - return mContentType; - } - - public int getCount() throws MessagingException { - return mParts.size(); - } - - public boolean removeBodyPart(BodyPart part) throws MessagingException { - return mParts.remove(part); - } - - public void removeBodyPart(int index) throws MessagingException { - mParts.remove(index); - } - - public Part getParent() throws MessagingException { - return mParent; - } - - public void setParent(Part parent) throws MessagingException { - this.mParent = parent; - } -} diff --git a/src/com/fsck/k9/mail/NoSuchProviderException.java b/src/com/fsck/k9/mail/NoSuchProviderException.java deleted file mode 100644 index 5eb9029d0..000000000 --- a/src/com/fsck/k9/mail/NoSuchProviderException.java +++ /dev/null @@ -1,14 +0,0 @@ - -package com.fsck.k9.mail; - -public class NoSuchProviderException extends MessagingException { - public static final long serialVersionUID = -1; - - public NoSuchProviderException(String message) { - super(message); - } - - public NoSuchProviderException(String message, Throwable throwable) { - super(message, throwable); - } -} diff --git a/src/com/fsck/k9/mail/Part.java b/src/com/fsck/k9/mail/Part.java deleted file mode 100644 index 2d06744ed..000000000 --- a/src/com/fsck/k9/mail/Part.java +++ /dev/null @@ -1,31 +0,0 @@ - -package com.fsck.k9.mail; - -import java.io.IOException; -import java.io.OutputStream; - -public interface Part { - public void addHeader(String name, String value) throws MessagingException; - - public void removeHeader(String name) throws MessagingException; - - public void setHeader(String name, String value) throws MessagingException; - - public Body getBody() throws MessagingException; - - public String getContentType() throws MessagingException; - - public String getDisposition() throws MessagingException; - - public String[] getHeader(String name) throws MessagingException; - - public int getSize() throws MessagingException; - - public boolean isMimeType(String mimeType) throws MessagingException; - - public String getMimeType() throws MessagingException; - - public void setBody(Body body) throws MessagingException; - - public void writeTo(OutputStream out) throws IOException, MessagingException; -} diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java deleted file mode 100644 index 9f7474ac8..000000000 --- a/src/com/fsck/k9/mail/Store.java +++ /dev/null @@ -1,76 +0,0 @@ - -package com.fsck.k9.mail; - -import java.util.HashMap; - -import android.app.Application; - -import com.fsck.k9.mail.store.ImapStore; -import com.fsck.k9.mail.store.LocalStore; -import com.fsck.k9.mail.store.Pop3Store; - -/** - * Store is the access point for an email message store. It's location can be - * local or remote and no specific protocol is defined. Store is intended to - * loosely model in combination the JavaMail classes javax.mail.Store and - * javax.mail.Folder along with some additional functionality to improve - * performance on mobile devices. Implementations of this class should focus on - * making as few network connections as possible. - */ -public abstract class Store { - /** - * A global suggestion to Store implementors on how much of the body - * should be returned on FetchProfile.Item.BODY_SANE requests. - */ - public static final int FETCH_BODY_SANE_SUGGESTED_SIZE = (50 * 1024); - - protected static final int SOCKET_CONNECT_TIMEOUT = 10000; - protected static final int SOCKET_READ_TIMEOUT = 60000; - - private static HashMap mStores = new HashMap(); - - /** - * Get an instance of a mail store. The URI is parsed as a standard URI and - * the scheme is used to determine which protocol will be used. The - * following schemes are currently recognized: imap - IMAP with no - * connection security. Ex: imap://username:password@host/ imap+tls - IMAP - * with TLS connection security, if the server supports it. Ex: - * imap+tls://username:password@host imap+tls+ - IMAP with required TLS - * connection security. Connection fails if TLS is not available. Ex: - * imap+tls+://username:password@host imap+ssl+ - IMAP with required SSL - * connection security. Connection fails if SSL is not available. Ex: - * imap+ssl+://username:password@host - * - * @param uri The URI of the store. - * @return - * @throws MessagingException - */ - public synchronized static Store getInstance(String uri, Application application) throws MessagingException { - Store store = mStores.get(uri); - if (store == null) { - if (uri.startsWith("imap")) { - store = new ImapStore(uri); - } else if (uri.startsWith("pop3")) { - store = new Pop3Store(uri); - } else if (uri.startsWith("local")) { - store = new LocalStore(uri, application); - } - - if (store != null) { - mStores.put(uri, store); - } - } - - if (store == null) { - throw new MessagingException("Unable to locate an applicable Store for " + uri); - } - - return store; - } - - public abstract Folder getFolder(String name) throws MessagingException; - - public abstract Folder[] getPersonalNamespaces() throws MessagingException; - - public abstract void checkSettings() throws MessagingException; -} diff --git a/src/com/fsck/k9/mail/Transport.java b/src/com/fsck/k9/mail/Transport.java deleted file mode 100644 index eba3f8969..000000000 --- a/src/com/fsck/k9/mail/Transport.java +++ /dev/null @@ -1,22 +0,0 @@ - -package com.fsck.k9.mail; - -import com.fsck.k9.mail.transport.SmtpTransport; - -public abstract class Transport { - protected static final int SOCKET_CONNECT_TIMEOUT = 10000; - - public synchronized static Transport getInstance(String uri) throws MessagingException { - if (uri.startsWith("smtp")) { - return new SmtpTransport(uri); - } else { - throw new MessagingException("Unable to locate an applicable Transport for " + uri); - } - } - - public abstract void open() throws MessagingException; - - public abstract void sendMessage(Message message) throws MessagingException; - - public abstract void close() throws MessagingException; -} diff --git a/src/com/fsck/k9/mail/internet/BinaryTempFileBody.java b/src/com/fsck/k9/mail/internet/BinaryTempFileBody.java deleted file mode 100644 index 771c17c5e..000000000 --- a/src/com/fsck/k9/mail/internet/BinaryTempFileBody.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.fsck.k9.mail.internet; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.apache.commons.io.IOUtils; - -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.codec.binary.Base64OutputStream; -import com.fsck.k9.mail.Body; -import com.fsck.k9.mail.MessagingException; - -/** - * A Body that is backed by a temp file. The Body exposes a getOutputStream method that allows - * the user to write to the temp file. After the write the body is available via getInputStream - * and writeTo one time. After writeTo is called, or the InputStream returned from - * getInputStream is closed the file is deleted and the Body should be considered disposed of. - */ -public class BinaryTempFileBody implements Body { - private static File mTempDirectory; - - private File mFile; - - public static void setTempDirectory(File tempDirectory) { - mTempDirectory = tempDirectory; - } - - public BinaryTempFileBody() throws IOException { - if (mTempDirectory == null) { - throw new - RuntimeException("setTempDirectory has not been called on BinaryTempFileBody!"); - } - } - - public OutputStream getOutputStream() throws IOException { - mFile = File.createTempFile("body", null, mTempDirectory); - mFile.deleteOnExit(); - return new FileOutputStream(mFile); - } - - public InputStream getInputStream() throws MessagingException { - try { - return new BinaryTempFileBodyInputStream(new FileInputStream(mFile)); - } - catch (IOException ioe) { - throw new MessagingException("Unable to open body", ioe); - } - } - - public void writeTo(OutputStream out) throws IOException, MessagingException { - InputStream in = getInputStream(); - Base64OutputStream base64Out = new Base64OutputStream(out); - IOUtils.copy(in, base64Out); - base64Out.close(); - mFile.delete(); - } - - class BinaryTempFileBodyInputStream extends FilterInputStream { - public BinaryTempFileBodyInputStream(InputStream in) { - super(in); - } - - @Override - public void close() throws IOException { - super.close(); - mFile.delete(); - } - } -} diff --git a/src/com/fsck/k9/mail/internet/MimeBodyPart.java b/src/com/fsck/k9/mail/internet/MimeBodyPart.java deleted file mode 100644 index 4504a99a8..000000000 --- a/src/com/fsck/k9/mail/internet/MimeBodyPart.java +++ /dev/null @@ -1,121 +0,0 @@ - -package com.fsck.k9.mail.internet; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; - -import com.fsck.k9.mail.Body; -import com.fsck.k9.mail.BodyPart; -import com.fsck.k9.mail.MessagingException; - -/** - * TODO this is a close approximation of Message, need to update along with - * Message. - */ -public class MimeBodyPart extends BodyPart { - protected MimeHeader mHeader = new MimeHeader(); - protected Body mBody; - protected int mSize; - - public MimeBodyPart() throws MessagingException { - this(null); - } - - public MimeBodyPart(Body body) throws MessagingException { - this(body, null); - } - - public MimeBodyPart(Body body, String mimeType) throws MessagingException { - if (mimeType != null) { - setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType); - } - setBody(body); - } - - protected String getFirstHeader(String name) throws MessagingException { - return mHeader.getFirstHeader(name); - } - - public void addHeader(String name, String value) throws MessagingException { - mHeader.addHeader(name, value); - } - - public void setHeader(String name, String value) throws MessagingException { - mHeader.setHeader(name, value); - } - - public String[] getHeader(String name) throws MessagingException { - return mHeader.getHeader(name); - } - - public void removeHeader(String name) throws MessagingException { - mHeader.removeHeader(name); - } - - public Body getBody() throws MessagingException { - return mBody; - } - - public void setBody(Body body) throws MessagingException { - this.mBody = body; - if (body instanceof com.fsck.k9.mail.Multipart) { - com.fsck.k9.mail.Multipart multipart = ((com.fsck.k9.mail.Multipart)body); - multipart.setParent(this); - setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType()); - } - else if (body instanceof TextBody) { - String contentType = String.format("%s;\n charset=utf-8", getMimeType()); - String name = MimeUtility.getHeaderParameter(getContentType(), "name"); - if (name != null) { - contentType += String.format(";\n name=\"%s\"", name); - } - setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType); - setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); - } - } - - public String getContentType() throws MessagingException { - String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE); - if (contentType == null) { - return "text/plain"; - } else { - return contentType; - } - } - - public String getDisposition() throws MessagingException { - String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION); - if (contentDisposition == null) { - return null; - } else { - return contentDisposition; - } - } - - public String getMimeType() throws MessagingException { - return MimeUtility.getHeaderParameter(getContentType(), null); - } - - public boolean isMimeType(String mimeType) throws MessagingException { - return getMimeType().equals(mimeType); - } - - public int getSize() throws MessagingException { - return mSize; - } - - /** - * Write the MimeMessage out in MIME format. - */ - public void writeTo(OutputStream out) throws IOException, MessagingException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - mHeader.writeTo(out); - writer.write("\r\n"); - writer.flush(); - if (mBody != null) { - mBody.writeTo(out); - } - } -} diff --git a/src/com/fsck/k9/mail/internet/MimeHeader.java b/src/com/fsck/k9/mail/internet/MimeHeader.java deleted file mode 100644 index 35b50c357..000000000 --- a/src/com/fsck/k9/mail/internet/MimeHeader.java +++ /dev/null @@ -1,105 +0,0 @@ - -package com.fsck.k9.mail.internet; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.ArrayList; - -import com.fsck.k9.Utility; -import com.fsck.k9.mail.MessagingException; - -public class MimeHeader { - /** - * Application specific header that contains Store specific information about an attachment. - * In IMAP this contains the IMAP BODYSTRUCTURE part id so that the ImapStore can later - * retrieve the attachment at will from the server. - * The info is recorded from this header on LocalStore.appendMessages and is put back - * into the MIME data by LocalStore.fetch. - */ - public static final String HEADER_ANDROID_ATTACHMENT_STORE_DATA = "X-Android-Attachment-StoreData"; - - public static final String HEADER_CONTENT_TYPE = "Content-Type"; - public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; - public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; - - /** - * Fields that should be omitted when writing the header using writeTo() - */ - private static final String[] writeOmitFields = { -// HEADER_ANDROID_ATTACHMENT_DOWNLOADED, -// HEADER_ANDROID_ATTACHMENT_ID, - HEADER_ANDROID_ATTACHMENT_STORE_DATA - }; - - protected ArrayList mFields = new ArrayList(); - - public void clear() { - mFields.clear(); - } - - public String getFirstHeader(String name) throws MessagingException { - String[] header = getHeader(name); - if (header == null) { - return null; - } - return header[0]; - } - - public void addHeader(String name, String value) throws MessagingException { - mFields.add(new Field(name, MimeUtility.foldAndEncode(value))); - } - - public void setHeader(String name, String value) throws MessagingException { - if (name == null || value == null) { - return; - } - removeHeader(name); - addHeader(name, value); - } - - public String[] getHeader(String name) throws MessagingException { - ArrayList values = new ArrayList(); - for (Field field : mFields) { - if (field.name.equalsIgnoreCase(name)) { - values.add(field.value); - } - } - if (values.size() == 0) { - return null; - } - return values.toArray(new String[] {}); - } - - public void removeHeader(String name) throws MessagingException { - ArrayList removeFields = new ArrayList(); - for (Field field : mFields) { - if (field.name.equalsIgnoreCase(name)) { - removeFields.add(field); - } - } - mFields.removeAll(removeFields); - } - - public void writeTo(OutputStream out) throws IOException, MessagingException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - for (Field field : mFields) { - if (!Utility.arrayContains(writeOmitFields, field.name)) { - writer.write(field.name + ": " + field.value + "\r\n"); - } - } - writer.flush(); - } - - class Field { - String name; - - String value; - - public Field(String name, String value) { - this.name = name; - this.value = value; - } - } -} diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java deleted file mode 100644 index 41d32fd5f..000000000 --- a/src/com/fsck/k9/mail/internet/MimeMessage.java +++ /dev/null @@ -1,424 +0,0 @@ - -package com.fsck.k9.mail.internet; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Stack; - -import org.apache.james.mime4j.BodyDescriptor; -import org.apache.james.mime4j.ContentHandler; -import org.apache.james.mime4j.EOLConvertingInputStream; -import org.apache.james.mime4j.MimeStreamParser; -import org.apache.james.mime4j.field.DateTimeField; -import org.apache.james.mime4j.field.Field; - -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.Body; -import com.fsck.k9.mail.BodyPart; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Part; - -/** - * An implementation of Message that stores all of it's metadata in RFC 822 and - * RFC 2045 style headers. - */ -public class MimeMessage extends Message { - protected MimeHeader mHeader = new MimeHeader(); - protected Address[] mFrom; - protected Address[] mTo; - protected Address[] mCc; - protected Address[] mBcc; - protected Address[] mReplyTo; - protected Date mSentDate; - protected SimpleDateFormat mDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z"); - protected Body mBody; - protected int mSize; - - public MimeMessage() { - /* - * Every new messages gets a Message-ID - */ - try { - setHeader("Message-ID", generateMessageId()); - } - catch (MessagingException me) { - throw new RuntimeException("Unable to create MimeMessage", me); - } - } - - private String generateMessageId() { - StringBuffer sb = new StringBuffer(); - sb.append("<"); - for (int i = 0; i < 24; i++) { - sb.append(Integer.toString((int)(Math.random() * 35), 36)); - } - sb.append("."); - sb.append(Long.toString(System.currentTimeMillis())); - sb.append("@email.android.com>"); - return sb.toString(); - } - - /** - * Parse the given InputStream using Apache Mime4J to build a MimeMessage. - * - * @param in - * @throws IOException - * @throws MessagingException - */ - public MimeMessage(InputStream in) throws IOException, MessagingException { - parse(in); - } - - protected void parse(InputStream in) throws IOException, MessagingException { - mHeader.clear(); - mBody = null; - mBcc = null; - mTo = null; - mFrom = null; - mSentDate = null; - - MimeStreamParser parser = new MimeStreamParser(); - parser.setContentHandler(new MimeMessageBuilder()); - parser.parse(new EOLConvertingInputStream(in)); - } - - public Date getReceivedDate() throws MessagingException { - return null; - } - - public Date getSentDate() throws MessagingException { - if (mSentDate == null) { - try { - DateTimeField field = (DateTimeField)Field.parse("Date: " - + MimeUtility.unfoldAndDecode(getFirstHeader("Date"))); - mSentDate = field.getDate(); - } catch (Exception e) { - - } - } - return mSentDate; - } - - public void setSentDate(Date sentDate) throws MessagingException { - setHeader("Date", mDateFormat.format(sentDate)); - this.mSentDate = sentDate; - } - - public String getContentType() throws MessagingException { - String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE); - if (contentType == null) { - return "text/plain"; - } else { - return contentType; - } - } - - public String getDisposition() throws MessagingException { - String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION); - if (contentDisposition == null) { - return null; - } else { - return contentDisposition; - } - } - - public String getMimeType() throws MessagingException { - return MimeUtility.getHeaderParameter(getContentType(), null); - } - - public int getSize() throws MessagingException { - return mSize; - } - - /** - * Returns a list of the given recipient type from this message. If no addresses are - * found the method returns an empty array. - */ - public Address[] getRecipients(RecipientType type) throws MessagingException { - if (type == RecipientType.TO) { - if (mTo == null) { - mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To"))); - } - return mTo; - } else if (type == RecipientType.CC) { - if (mCc == null) { - mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC"))); - } - return mCc; - } else if (type == RecipientType.BCC) { - if (mBcc == null) { - mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC"))); - } - return mBcc; - } else { - throw new MessagingException("Unrecognized recipient type."); - } - } - - public void setRecipients(RecipientType type, Address[] addresses) throws MessagingException { - if (type == RecipientType.TO) { - if (addresses == null || addresses.length == 0) { - removeHeader("To"); - this.mTo = null; - } else { - setHeader("To", Address.toString(addresses)); - this.mTo = addresses; - } - } else if (type == RecipientType.CC) { - if (addresses == null || addresses.length == 0) { - removeHeader("CC"); - this.mCc = null; - } else { - setHeader("CC", Address.toString(addresses)); - this.mCc = addresses; - } - } else if (type == RecipientType.BCC) { - if (addresses == null || addresses.length == 0) { - removeHeader("BCC"); - this.mBcc = null; - } else { - setHeader("BCC", Address.toString(addresses)); - this.mBcc = addresses; - } - } else { - throw new MessagingException("Unrecognized recipient type."); - } - } - - /** - * Returns the unfolded, decoded value of the Subject header. - */ - public String getSubject() throws MessagingException { - return MimeUtility.unfoldAndDecode(getFirstHeader("Subject")); - } - - public void setSubject(String subject) throws MessagingException { - setHeader("Subject", subject); - } - - public Address[] getFrom() throws MessagingException { - if (mFrom == null) { - String list = MimeUtility.unfold(getFirstHeader("From")); - if (list == null || list.length() == 0) { - list = MimeUtility.unfold(getFirstHeader("Sender")); - } - mFrom = Address.parse(list); - } - return mFrom; - } - - public void setFrom(Address from) throws MessagingException { - if (from != null) { - setHeader("From", from.toString()); - this.mFrom = new Address[] { - from - }; - } else { - this.mFrom = null; - } - } - - public Address[] getReplyTo() throws MessagingException { - if (mReplyTo == null) { - mReplyTo = Address.parse(MimeUtility.unfold(getFirstHeader("Reply-to"))); - } - return mReplyTo; - } - - public void setReplyTo(Address[] replyTo) throws MessagingException { - if (replyTo == null || replyTo.length == 0) { - removeHeader("Reply-to"); - mReplyTo = null; - } else { - setHeader("Reply-to", Address.toString(replyTo)); - mReplyTo = replyTo; - } - } - - public void saveChanges() throws MessagingException { - throw new MessagingException("saveChanges not yet implemented"); - } - - public Body getBody() throws MessagingException { - return mBody; - } - - public void setBody(Body body) throws MessagingException { - this.mBody = body; - if (body instanceof com.fsck.k9.mail.Multipart) { - com.fsck.k9.mail.Multipart multipart = ((com.fsck.k9.mail.Multipart)body); - multipart.setParent(this); - setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType()); - setHeader("MIME-Version", "1.0"); - } - else if (body instanceof TextBody) { - setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8", - getMimeType())); - setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); - } - } - - protected String getFirstHeader(String name) throws MessagingException { - return mHeader.getFirstHeader(name); - } - - public void addHeader(String name, String value) throws MessagingException { - mHeader.addHeader(name, value); - } - - public void setHeader(String name, String value) throws MessagingException { - mHeader.setHeader(name, value); - } - - public String[] getHeader(String name) throws MessagingException { - return mHeader.getHeader(name); - } - - public void removeHeader(String name) throws MessagingException { - mHeader.removeHeader(name); - } - - public void writeTo(OutputStream out) throws IOException, MessagingException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - mHeader.writeTo(out); - writer.write("\r\n"); - writer.flush(); - if (mBody != null) { - mBody.writeTo(out); - } - } - - public InputStream getInputStream() throws MessagingException { - return null; - } - - class MimeMessageBuilder implements ContentHandler { - private Stack stack = new Stack(); - - public MimeMessageBuilder() { - } - - private void expect(Class c) { - if (!c.isInstance(stack.peek())) { - throw new IllegalStateException("Internal stack error: " + "Expected '" - + c.getName() + "' found '" + stack.peek().getClass().getName() + "'"); - } - } - - public void startMessage() { - if (stack.isEmpty()) { - stack.push(MimeMessage.this); - } else { - expect(Part.class); - try { - MimeMessage m = new MimeMessage(); - ((Part)stack.peek()).setBody(m); - stack.push(m); - } catch (MessagingException me) { - throw new Error(me); - } - } - } - - public void endMessage() { - expect(MimeMessage.class); - stack.pop(); - } - - public void startHeader() { - expect(Part.class); - } - - public void field(String fieldData) { - expect(Part.class); - try { - String[] tokens = fieldData.split(":", 2); - ((Part)stack.peek()).addHeader(tokens[0], tokens[1].trim()); - } catch (MessagingException me) { - throw new Error(me); - } - } - - public void endHeader() { - expect(Part.class); - } - - public void startMultipart(BodyDescriptor bd) { - expect(Part.class); - - Part e = (Part)stack.peek(); - try { - MimeMultipart multiPart = new MimeMultipart(e.getContentType()); - e.setBody(multiPart); - stack.push(multiPart); - } catch (MessagingException me) { - throw new Error(me); - } - } - - public void body(BodyDescriptor bd, InputStream in) throws IOException { - expect(Part.class); - Body body = MimeUtility.decodeBody(in, bd.getTransferEncoding()); - try { - ((Part)stack.peek()).setBody(body); - } catch (MessagingException me) { - throw new Error(me); - } - } - - public void endMultipart() { - stack.pop(); - } - - public void startBodyPart() { - expect(MimeMultipart.class); - - try { - MimeBodyPart bodyPart = new MimeBodyPart(); - ((MimeMultipart)stack.peek()).addBodyPart(bodyPart); - stack.push(bodyPart); - } catch (MessagingException me) { - throw new Error(me); - } - } - - public void endBodyPart() { - expect(BodyPart.class); - stack.pop(); - } - - public void epilogue(InputStream is) throws IOException { - expect(MimeMultipart.class); - StringBuffer sb = new StringBuffer(); - int b; - while ((b = is.read()) != -1) { - sb.append((char)b); - } - // ((Multipart) stack.peek()).setEpilogue(sb.toString()); - } - - public void preamble(InputStream is) throws IOException { - expect(MimeMultipart.class); - StringBuffer sb = new StringBuffer(); - int b; - while ((b = is.read()) != -1) { - sb.append((char)b); - } - try { - ((MimeMultipart)stack.peek()).setPreamble(sb.toString()); - } catch (MessagingException me) { - throw new Error(me); - } - } - - public void raw(InputStream is) throws IOException { - throw new UnsupportedOperationException("Not supported"); - } - } -} diff --git a/src/com/fsck/k9/mail/internet/MimeMultipart.java b/src/com/fsck/k9/mail/internet/MimeMultipart.java deleted file mode 100644 index 6db58a5d8..000000000 --- a/src/com/fsck/k9/mail/internet/MimeMultipart.java +++ /dev/null @@ -1,95 +0,0 @@ - -package com.fsck.k9.mail.internet; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; - -import com.fsck.k9.mail.BodyPart; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Multipart; - -public class MimeMultipart extends Multipart { - protected String mPreamble; - - protected String mContentType; - - protected String mBoundary; - - protected String mSubType; - - public MimeMultipart() throws MessagingException { - mBoundary = generateBoundary(); - setSubType("mixed"); - } - - public MimeMultipart(String contentType) throws MessagingException { - this.mContentType = contentType; - try { - mSubType = MimeUtility.getHeaderParameter(contentType, null).split("/")[1]; - mBoundary = MimeUtility.getHeaderParameter(contentType, "boundary"); - if (mBoundary == null) { - throw new MessagingException("MultiPart does not contain boundary: " + contentType); - } - } catch (Exception e) { - throw new MessagingException( - "Invalid MultiPart Content-Type; must contain subtype and boundary. (" - + contentType + ")", e); - } - } - - public String generateBoundary() { - StringBuffer sb = new StringBuffer(); - sb.append("----"); - for (int i = 0; i < 30; i++) { - sb.append(Integer.toString((int)(Math.random() * 35), 36)); - } - return sb.toString().toUpperCase(); - } - - public String getPreamble() throws MessagingException { - return mPreamble; - } - - public void setPreamble(String preamble) throws MessagingException { - this.mPreamble = preamble; - } - - public String getContentType() throws MessagingException { - return mContentType; - } - - public void setSubType(String subType) throws MessagingException { - this.mSubType = subType; - mContentType = String.format("multipart/%s; boundary=\"%s\"", subType, mBoundary); - } - - public void writeTo(OutputStream out) throws IOException, MessagingException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); - - if (mPreamble != null) { - writer.write(mPreamble + "\r\n"); - } - - if(mParts.size() == 0){ - writer.write("--" + mBoundary + "\r\n"); - } - - for (int i = 0, count = mParts.size(); i < count; i++) { - BodyPart bodyPart = (BodyPart)mParts.get(i); - writer.write("--" + mBoundary + "\r\n"); - writer.flush(); - bodyPart.writeTo(out); - writer.write("\r\n"); - } - - writer.write("--" + mBoundary + "--\r\n"); - writer.flush(); - } - - public InputStream getInputStream() throws MessagingException { - return null; - } -} diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java deleted file mode 100644 index 2066eb8d6..000000000 --- a/src/com/fsck/k9/mail/internet/MimeUtility.java +++ /dev/null @@ -1,304 +0,0 @@ - -package com.fsck.k9.mail.internet; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; - -import org.apache.commons.io.IOUtils; -import org.apache.james.mime4j.decoder.Base64InputStream; -import org.apache.james.mime4j.decoder.DecoderUtil; -import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; -import org.apache.james.mime4j.util.CharsetUtil; - -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.mail.Body; -import com.fsck.k9.mail.BodyPart; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Multipart; -import com.fsck.k9.mail.Part; - -public class MimeUtility { - public static String unfold(String s) { - if (s == null) { - return null; - } - return s.replaceAll("\r|\n", ""); - } - - public static String decode(String s) { - if (s == null) { - return null; - } - return DecoderUtil.decodeEncodedWords(s); - } - - public static String unfoldAndDecode(String s) { - return decode(unfold(s)); - } - - // TODO implement proper foldAndEncode - public static String foldAndEncode(String s) { - return s; - } - - /** - * Returns the named parameter of a header field. If name is null the first - * parameter is returned, or if there are no additional parameters in the - * field the entire field is returned. Otherwise the named parameter is - * searched for in a case insensitive fashion and returned. If the parameter - * cannot be found the method returns null. - * - * @param header - * @param name - * @return - */ - public static String getHeaderParameter(String header, String name) { - if (header == null) { - return null; - } - header = header.replaceAll("\r|\n", ""); - String[] parts = header.split(";"); - if (name == null) { - return parts[0]; - } - for (String part : parts) { - if (part.trim().toLowerCase().startsWith(name.toLowerCase())) { - String parameter = part.split("=", 2)[1].trim(); - if (parameter.startsWith("\"") && parameter.endsWith("\"")) { - return parameter.substring(1, parameter.length() - 1); - } - else { - return parameter; - } - } - } - return null; - } - - public static Part findFirstPartByMimeType(Part part, String mimeType) - throws MessagingException { - if (part.getBody() instanceof Multipart) { - Multipart multipart = (Multipart)part.getBody(); - for (int i = 0, count = multipart.getCount(); i < count; i++) { - BodyPart bodyPart = multipart.getBodyPart(i); - Part ret = findFirstPartByMimeType(bodyPart, mimeType); - if (ret != null) { - return ret; - } - } - } - else if (part.getMimeType().equalsIgnoreCase(mimeType)) { - return part; - } - return null; - } - - public static Part findPartByContentId(Part part, String contentId) throws Exception { - if (part.getBody() instanceof Multipart) { - Multipart multipart = (Multipart)part.getBody(); - for (int i = 0, count = multipart.getCount(); i < count; i++) { - BodyPart bodyPart = multipart.getBodyPart(i); - Part ret = findPartByContentId(bodyPart, contentId); - if (ret != null) { - return ret; - } - } - } - String[] header = part.getHeader("Content-ID"); - if (header != null) { - for (String s : header) { - if (s.equals(contentId)) { - return part; - } - } - } - return null; - } - - /** - * Reads the Part's body and returns a String based on any charset conversion that needed - * to be done. - * @param part - * @return - * @throws IOException - */ - public static String getTextFromPart(Part part) { - try { - if (part != null && part.getBody() != null) { - InputStream in = part.getBody().getInputStream(); - String mimeType = part.getMimeType(); - if (mimeType != null && MimeUtility.mimeTypeMatches(mimeType, "text/*")) { - /* - * Now we read the part into a buffer for further processing. Because - * the stream is now wrapped we'll remove any transfer encoding at this point. - */ - ByteArrayOutputStream out = new ByteArrayOutputStream(); - IOUtils.copy(in, out); - - byte[] bytes = out.toByteArray(); - in.close(); - out.close(); - - String charset = getHeaderParameter(part.getContentType(), "charset"); - /* - * We've got a text part, so let's see if it needs to be processed further. - */ - if (charset != null) { - /* - * See if there is conversion from the MIME charset to the Java one. - */ - charset = CharsetUtil.toJavaCharset(charset); - } - if (charset != null) { - /* - * We've got a charset encoding, so decode using it. - */ - return new String(bytes, 0, bytes.length, charset); - } - else { - /* - * No encoding, so use us-ascii, which is the standard. - */ - return new String(bytes, 0, bytes.length, "ASCII"); - } - } - } - - } - catch (Exception e) { - /* - * If we are not able to process the body there's nothing we can do about it. Return - * null and let the upper layers handle the missing content. - */ - Log.e(k9.LOG_TAG, "Unable to getTextFromPart", e); - } - return null; - } - - /** - * Returns true if the given mimeType matches the matchAgainst specification. - * @param mimeType A MIME type to check. - * @param matchAgainst A MIME type to check against. May include wildcards such as image/* or - * * /*. - * @return - */ - public static boolean mimeTypeMatches(String mimeType, String matchAgainst) { - return mimeType.matches(matchAgainst.replaceAll("\\*", "\\.\\*")); - } - - /** - * Returns true if the given mimeType matches any of the matchAgainst specifications. - * @param mimeType A MIME type to check. - * @param matchAgainst An array of MIME types to check against. May include wildcards such - * as image/* or * /*. - * @return - */ - public static boolean mimeTypeMatches(String mimeType, String[] matchAgainst) { - for (String matchType : matchAgainst) { - if (mimeType.matches(matchType.replaceAll("\\*", "\\.\\*"))) { - return true; - } - } - return false; - } - - /** - * Removes any content transfer encoding from the stream and returns a Body. - */ - public static Body decodeBody(InputStream in, String contentTransferEncoding) - throws IOException { - /* - * We'll remove any transfer encoding by wrapping the stream. - */ - if (contentTransferEncoding != null) { - contentTransferEncoding = - MimeUtility.getHeaderParameter(contentTransferEncoding, null); - if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) { - in = new QuotedPrintableInputStream(in); - } - else if ("base64".equalsIgnoreCase(contentTransferEncoding)) { - in = new Base64InputStream(in); - } - } - - BinaryTempFileBody tempBody = new BinaryTempFileBody(); - OutputStream out = tempBody.getOutputStream(); - IOUtils.copy(in, out); - out.close(); - return tempBody; - } - - /** - * An unfortunately named method that makes decisions about a Part (usually a Message) - * as to which of it's children will be "viewable" and which will be attachments. - * The method recursively sorts the viewables and attachments into seperate - * lists for further processing. - * @param part - * @param viewables - * @param attachments - * @throws MessagingException - */ - public static void collectParts(Part part, ArrayList viewables, - ArrayList attachments) throws MessagingException { - String disposition = part.getDisposition(); - String dispositionType = null; - String dispositionFilename = null; - if (disposition != null) { - dispositionType = MimeUtility.getHeaderParameter(disposition, null); - dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename"); - } - - /* - * A best guess that this part is intended to be an attachment and not inline. - */ - boolean attachment = ("attachment".equalsIgnoreCase(dispositionType)) - || (dispositionFilename != null) - && (!"inline".equalsIgnoreCase(dispositionType)); - - /* - * If the part is Multipart but not alternative it's either mixed or - * something we don't know about, which means we treat it as mixed - * per the spec. We just process it's pieces recursively. - */ - if (part.getBody() instanceof Multipart) { - Multipart mp = (Multipart)part.getBody(); - for (int i = 0; i < mp.getCount(); i++) { - collectParts(mp.getBodyPart(i), viewables, attachments); - } - } - /* - * If the part is an embedded message we just continue to process - * it, pulling any viewables or attachments into the running list. - */ - else if (part.getBody() instanceof Message) { - Message message = (Message)part.getBody(); - collectParts(message, viewables, attachments); - } - /* - * If the part is HTML and it got this far it's part of a mixed (et - * al) and should be rendered inline. - */ - else if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/html"))) { - viewables.add(part); - } - /* - * If the part is plain text and it got this far it's part of a - * mixed (et al) and should be rendered inline. - */ - else if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/plain"))) { - viewables.add(part); - } - /* - * Finally, if it's nothing else we will include it as an attachment. - */ - else { - attachments.add(part); - } - } -} diff --git a/src/com/fsck/k9/mail/internet/TextBody.java b/src/com/fsck/k9/mail/internet/TextBody.java deleted file mode 100644 index 0b85ba115..000000000 --- a/src/com/fsck/k9/mail/internet/TextBody.java +++ /dev/null @@ -1,47 +0,0 @@ - -package com.fsck.k9.mail.internet; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; - - -import com.fsck.k9.codec.binary.Base64; -import com.fsck.k9.mail.Body; -import com.fsck.k9.mail.MessagingException; - -public class TextBody implements Body { - String mBody; - - public TextBody(String body) { - this.mBody = body; - } - - public void writeTo(OutputStream out) throws IOException, MessagingException { - byte[] bytes = mBody.getBytes("UTF-8"); - out.write(Base64.encodeBase64Chunked(bytes)); - } - - /** - * Get the text of the body in it's unencoded format. - * @return - */ - public String getText() { - return mBody; - } - - /** - * Returns an InputStream that reads this body's text in UTF-8 format. - */ - public InputStream getInputStream() throws MessagingException { - try { - byte[] b = mBody.getBytes("UTF-8"); - return new ByteArrayInputStream(b); - } - catch (UnsupportedEncodingException usee) { - return null; - } - } -} diff --git a/src/com/fsck/k9/mail/store/ImapResponseParser.java b/src/com/fsck/k9/mail/store/ImapResponseParser.java deleted file mode 100644 index 6a759e53c..000000000 --- a/src/com/fsck/k9/mail/store/ImapResponseParser.java +++ /dev/null @@ -1,356 +0,0 @@ -/** - * - */ - -package com.fsck.k9.mail.store; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; - -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.FixedLengthInputStream; -import com.fsck.k9.PeekableInputStream; -import com.fsck.k9.mail.MessagingException; - -public class ImapResponseParser { - SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z"); - PeekableInputStream mIn; - InputStream mActiveLiteral; - - public ImapResponseParser(PeekableInputStream in) { - this.mIn = in; - } - - /** - * Reads the next response available on the stream and returns an - * ImapResponse object that represents it. - * - * @return - * @throws IOException - */ - public ImapResponse readResponse() throws IOException { - ImapResponse response = new ImapResponse(); - if (mActiveLiteral != null) { - while (mActiveLiteral.read() != -1) - ; - mActiveLiteral = null; - } - int ch = mIn.peek(); - if (ch == '*') { - parseUntaggedResponse(); - readTokens(response); - } else if (ch == '+') { - response.mCommandContinuationRequested = - parseCommandContinuationRequest(); - readTokens(response); - } else { - response.mTag = parseTaggedResponse(); - readTokens(response); - } - if (Config.LOGD) { - if (k9.DEBUG) { - Log.d(k9.LOG_TAG, "<<< " + response.toString()); - } - } - return response; - } - - private void readTokens(ImapResponse response) throws IOException { - response.clear(); - Object token; - while ((token = readToken()) != null) { - if (response != null) { - response.add(token); - } - if (mActiveLiteral != null) { - break; - } - } - response.mCompleted = token == null; - } - - /** - * Reads the next token of the response. The token can be one of: String - - * for NIL, QUOTED, NUMBER, ATOM. InputStream - for LITERAL. - * InputStream.available() returns the total length of the stream. - * ImapResponseList - for PARENTHESIZED LIST. Can contain any of the above - * elements including List. - * - * @return The next token in the response or null if there are no more - * tokens. - * @throws IOException - */ - public Object readToken() throws IOException { - while (true) { - Object token = parseToken(); - if (token == null || !token.equals(")")) { - return token; - } - } - } - - private Object parseToken() throws IOException { - if (mActiveLiteral != null) { - while (mActiveLiteral.read() != -1) - ; - mActiveLiteral = null; - } - while (true) { - int ch = mIn.peek(); - if (ch == '(') { - return parseList(); - } else if (ch == ')') { - expect(')'); - return ")"; - } else if (ch == '"') { - return parseQuoted(); - } else if (ch == '{') { - mActiveLiteral = parseLiteral(); - return mActiveLiteral; - } else if (ch == ' ') { - expect(' '); - } else if (ch == '\r') { - expect('\r'); - expect('\n'); - return null; - } else if (ch == '\n') { - expect('\n'); - return null; - } else if (ch == '\t') { - expect('\t'); - } else { - return parseAtom(); - } - } - } - - private boolean parseCommandContinuationRequest() throws IOException { - expect('+'); - expect(' '); - return true; - } - - // * OK [UIDNEXT 175] Predicted next UID - private void parseUntaggedResponse() throws IOException { - expect('*'); - expect(' '); - } - - // 3 OK [READ-WRITE] Select completed. - private String parseTaggedResponse() throws IOException { - String tag = readStringUntil(' '); - return tag; - } - - private ImapList parseList() throws IOException { - expect('('); - ImapList list = new ImapList(); - Object token; - while (true) { - token = parseToken(); - if (token == null) { - break; - } else if (token instanceof InputStream) { - list.add(token); - break; - } else if (token.equals(")")) { - break; - } else { - list.add(token); - } - } - return list; - } - - private String parseAtom() throws IOException { - StringBuffer sb = new StringBuffer(); - int ch; - while (true) { - ch = mIn.peek(); - if (ch == -1) { - throw new IOException("parseAtom(): end of stream reached"); - } else if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' || - // docs claim that flags are \ atom but atom isn't supposed to - // contain - // * and some falgs contain * - // ch == '%' || ch == '*' || - ch == '%' || - // TODO probably should not allow \ and should recognize - // it as a flag instead - // ch == '"' || ch == '\' || - ch == '"' || (ch >= 0x00 && ch <= 0x1f) || ch == 0x7f) { - if (sb.length() == 0) { - throw new IOException(String.format("parseAtom(): (%04x %c)", (int)ch, ch)); - } - return sb.toString(); - } else { - sb.append((char)mIn.read()); - } - } - } - - /** - * A { has been read, read the rest of the size string, the space and then - * notify the listener with an InputStream. - * - * @param mListener - * @throws IOException - */ - private InputStream parseLiteral() throws IOException { - expect('{'); - int size = Integer.parseInt(readStringUntil('}')); - expect('\r'); - expect('\n'); - FixedLengthInputStream fixed = new FixedLengthInputStream(mIn, size); - return fixed; - } - - /** - * A " has been read, read to the end of the quoted string and notify the - * listener. - * - * @param mListener - * @throws IOException - */ - private String parseQuoted() throws IOException { - expect('"'); - return readStringUntil('"'); - } - - private String readStringUntil(char end) throws IOException { - StringBuffer sb = new StringBuffer(); - int ch; - while ((ch = mIn.read()) != -1) { - if (ch == end) { - return sb.toString(); - } else { - sb.append((char)ch); - } - } - throw new IOException("readQuotedString(): end of stream reached"); - } - - private int expect(char ch) throws IOException { - int d; - if ((d = mIn.read()) != ch) { - throw new IOException(String.format("Expected %04x (%c) but got %04x (%c)", (int)ch, - ch, d, (char)d)); - } - return d; - } - - /** - * Represents an IMAP LIST response and is also the base class for the - * ImapResponse. - */ - public class ImapList extends ArrayList { - public ImapList getList(int index) { - return (ImapList)get(index); - } - - public String getString(int index) { - return (String)get(index); - } - - public InputStream getLiteral(int index) { - return (InputStream)get(index); - } - - public int getNumber(int index) { - return Integer.parseInt(getString(index)); - } - - public Date getDate(int index) throws MessagingException { - try { - return mDateTimeFormat.parse(getString(index)); - } catch (ParseException pe) { - throw new MessagingException("Unable to parse IMAP datetime", pe); - } - } - - public Object getKeyedValue(Object key) { - for (int i = 0, count = size(); i < count; i++) { - if (get(i).equals(key)) { - return get(i + 1); - } - } - return null; - } - - public ImapList getKeyedList(Object key) { - return (ImapList)getKeyedValue(key); - } - - public String getKeyedString(Object key) { - return (String)getKeyedValue(key); - } - - public InputStream getKeyedLiteral(Object key) { - return (InputStream)getKeyedValue(key); - } - - public int getKeyedNumber(Object key) { - return Integer.parseInt(getKeyedString(key)); - } - - public Date getKeyedDate(Object key) throws MessagingException { - try { - String value = getKeyedString(key); - if (value == null) { - return null; - } - return mDateTimeFormat.parse(value); - } catch (ParseException pe) { - throw new MessagingException("Unable to parse IMAP datetime", pe); - } - } - } - - /** - * Represents a single response from the IMAP server. Tagged responses will - * have a non-null tag. Untagged responses will have a null tag. The object - * will contain all of the available tokens at the time the response is - * received. In general, it will either contain all of the tokens of the - * response or all of the tokens up until the first LITERAL. If the object - * does not contain the entire response the caller must call more() to - * continue reading the response until more returns false. - */ - public class ImapResponse extends ImapList { - private boolean mCompleted; - - boolean mCommandContinuationRequested; - String mTag; - - public boolean more() throws IOException { - if (mCompleted) { - return false; - } - readTokens(this); - return true; - } - - public String getAlertText() { - if (size() > 1 && "[ALERT]".equals(getString(1))) { - StringBuffer sb = new StringBuffer(); - for (int i = 2, count = size(); i < count; i++) { - sb.append(get(i).toString()); - sb.append(' '); - } - return sb.toString(); - } else { - return null; - } - } - - public String toString() { - return "#" + mTag + "# " + super.toString(); - } - } -} diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java deleted file mode 100644 index 43266e52d..000000000 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ /dev/null @@ -1,1283 +0,0 @@ - -package com.fsck.k9.mail.store; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.security.GeneralSecurityException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.SSLException; - -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.PeekableInputStream; -import com.fsck.k9.Utility; -import com.fsck.k9.mail.AuthenticationFailedException; -import com.fsck.k9.mail.FetchProfile; -import com.fsck.k9.mail.Flag; -import com.fsck.k9.mail.Folder; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessageRetrievalListener; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Part; -import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.CertificateValidationException; -import com.fsck.k9.mail.internet.MimeBodyPart; -import com.fsck.k9.mail.internet.MimeHeader; -import com.fsck.k9.mail.internet.MimeMessage; -import com.fsck.k9.mail.internet.MimeMultipart; -import com.fsck.k9.mail.internet.MimeUtility; -import com.fsck.k9.mail.store.ImapResponseParser.ImapList; -import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse; -import com.fsck.k9.mail.transport.CountingOutputStream; -import com.fsck.k9.mail.transport.EOLConvertingOutputStream; -import com.beetstra.jutf7.CharsetProvider; - -/** - *
- * TODO Need to start keeping track of UIDVALIDITY
- * TODO Need a default response handler for things like folder updates
- * TODO In fetch(), if we need a ImapMessage and were given
- * something else we can try to do a pre-fetch first.
- *
- * ftp://ftp.isi.edu/in-notes/rfc2683.txt When a client asks for
- * certain information in a FETCH command, the server may return the requested
- * information in any order, not necessarily in the order that it was requested.
- * Further, the server may return the information in separate FETCH responses
- * and may also return information that was not explicitly requested (to reflect
- * to the client changes in the state of the subject message).
- * 
- */ -public class ImapStore extends Store { - public static final int CONNECTION_SECURITY_NONE = 0; - public static final int CONNECTION_SECURITY_TLS_OPTIONAL = 1; - public static final int CONNECTION_SECURITY_TLS_REQUIRED = 2; - public static final int CONNECTION_SECURITY_SSL_REQUIRED = 3; - public static final int CONNECTION_SECURITY_SSL_OPTIONAL = 4; - - private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.SEEN }; - - private String mHost; - private int mPort; - private String mUsername; - private String mPassword; - private int mConnectionSecurity; - private String mPathPrefix; - - private LinkedList mConnections = - new LinkedList(); - - /** - * Charset used for converting folder names to and from UTF-7 as defined by RFC 3501. - */ - private Charset mModifiedUtf7Charset; - - /** - * Cache of ImapFolder objects. ImapFolders are attached to a given folder on the server - * and as long as their associated connection remains open they are reusable between - * requests. This cache lets us make sure we always reuse, if possible, for a given - * folder name. - */ - private HashMap mFolderCache = new HashMap(); - - /** - * imap://user:password@server:port CONNECTION_SECURITY_NONE - * imap+tls://user:password@server:port CONNECTION_SECURITY_TLS_OPTIONAL - * imap+tls+://user:password@server:port CONNECTION_SECURITY_TLS_REQUIRED - * imap+ssl+://user:password@server:port CONNECTION_SECURITY_SSL_REQUIRED - * imap+ssl://user:password@server:port CONNECTION_SECURITY_SSL_OPTIONAL - * - * @param _uri - */ - public ImapStore(String _uri) throws MessagingException { - URI uri; - try { - uri = new URI(_uri); - } catch (URISyntaxException use) { - throw new MessagingException("Invalid ImapStore URI", use); - } - - String scheme = uri.getScheme(); - if (scheme.equals("imap")) { - mConnectionSecurity = CONNECTION_SECURITY_NONE; - mPort = 143; - } else if (scheme.equals("imap+tls")) { - mConnectionSecurity = CONNECTION_SECURITY_TLS_OPTIONAL; - mPort = 143; - } else if (scheme.equals("imap+tls+")) { - mConnectionSecurity = CONNECTION_SECURITY_TLS_REQUIRED; - mPort = 143; - } else if (scheme.equals("imap+ssl+")) { - mConnectionSecurity = CONNECTION_SECURITY_SSL_REQUIRED; - mPort = 993; - } else if (scheme.equals("imap+ssl")) { - mConnectionSecurity = CONNECTION_SECURITY_SSL_OPTIONAL; - mPort = 993; - } else { - throw new MessagingException("Unsupported protocol"); - } - - mHost = uri.getHost(); - - if (uri.getPort() != -1) { - mPort = uri.getPort(); - } - - if (uri.getUserInfo() != null) { - String[] userInfoParts = uri.getUserInfo().split(":", 2); - mUsername = userInfoParts[0]; - if (userInfoParts.length > 1) { - mPassword = userInfoParts[1]; - } - } - - if ((uri.getPath() != null) && (uri.getPath().length() > 0)) { - mPathPrefix = uri.getPath().substring(1); - } - - mModifiedUtf7Charset = new CharsetProvider().charsetForName("X-RFC-3501"); - } - - @Override - public Folder getFolder(String name) throws MessagingException { - ImapFolder folder; - synchronized (mFolderCache) { - folder = mFolderCache.get(name); - if (folder == null) { - folder = new ImapFolder(name); - mFolderCache.put(name, folder); - } - } - return folder; - } - - - @Override - public Folder[] getPersonalNamespaces() throws MessagingException { - ImapConnection connection = getConnection(); - try { - ArrayList folders = new ArrayList(); - List responses = - connection.executeSimpleCommand(String.format("LIST \"\" \"%s*\"", - mPathPrefix == null ? "" : mPathPrefix)); - for (ImapResponse response : responses) { - if (response.get(0).equals("LIST")) { - boolean includeFolder = true; - String folder = decodeFolderName(response.getString(3)); - if (folder.equalsIgnoreCase("INBOX")) { - continue; - } - ImapList attributes = response.getList(1); - for (int i = 0, count = attributes.size(); i < count; i++) { - String attribute = attributes.getString(i); - if (attribute.equalsIgnoreCase("\\NoSelect")) { - includeFolder = false; - } - } - if (includeFolder) { - folders.add(getFolder(folder)); - } - } - } - folders.add(getFolder("INBOX")); - return folders.toArray(new Folder[] {}); - } catch (IOException ioe) { - connection.close(); - throw new MessagingException("Unable to get folder list.", ioe); - } finally { - releaseConnection(connection); - } - } - - @Override - public void checkSettings() throws MessagingException { - try { - ImapConnection connection = new ImapConnection(); - connection.open(); - connection.close(); - } - catch (IOException ioe) { - throw new MessagingException("Unable to connect.", ioe); - } - } - - /** - * Gets a connection if one is available for reuse, or creates a new one if not. - * @return - */ - private ImapConnection getConnection() throws MessagingException { - synchronized (mConnections) { - ImapConnection connection = null; - while ((connection = mConnections.poll()) != null) { - try { - connection.executeSimpleCommand("NOOP"); - break; - } - catch (IOException ioe) { - connection.close(); - } - } - if (connection == null) { - connection = new ImapConnection(); - } - return connection; - } - } - - private void releaseConnection(ImapConnection connection) { - mConnections.offer(connection); - } - - private String encodeFolderName(String name) { - try { - ByteBuffer bb = mModifiedUtf7Charset.encode(name); - byte[] b = new byte[bb.limit()]; - bb.get(b); - return new String(b, "US-ASCII"); - } - catch (UnsupportedEncodingException uee) { - /* - * The only thing that can throw this is getBytes("US-ASCII") and if US-ASCII doesn't - * exist we're totally screwed. - */ - throw new RuntimeException("Unabel to encode folder name: " + name, uee); - } - } - - private String decodeFolderName(String name) { - /* - * Convert the encoded name to US-ASCII, then pass it through the modified UTF-7 - * decoder and return the Unicode String. - */ - try { - byte[] encoded = name.getBytes("US-ASCII"); - CharBuffer cb = mModifiedUtf7Charset.decode(ByteBuffer.wrap(encoded)); - return cb.toString(); - } - catch (UnsupportedEncodingException uee) { - /* - * The only thing that can throw this is getBytes("US-ASCII") and if US-ASCII doesn't - * exist we're totally screwed. - */ - throw new RuntimeException("Unable to decode folder name: " + name, uee); - } - } - - class ImapFolder extends Folder { - private String mName; - private int mMessageCount = -1; - private ImapConnection mConnection; - private OpenMode mMode; - private boolean mExists; - - public ImapFolder(String name) { - this.mName = name; - } - - public void open(OpenMode mode) throws MessagingException { - if (isOpen() && mMode == mode) { - // Make sure the connection is valid. If it's not we'll close it down and continue - // on to get a new one. - try { - mConnection.executeSimpleCommand("NOOP"); - return; - } - catch (IOException ioe) { - ioExceptionHandler(mConnection, ioe); - } - } - synchronized (this) { - mConnection = getConnection(); - } - // * FLAGS (\Answered \Flagged \Deleted \Seen \Draft NonJunk - // $MDNSent) - // * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft - // NonJunk $MDNSent \*)] Flags permitted. - // * 23 EXISTS - // * 0 RECENT - // * OK [UIDVALIDITY 1125022061] UIDs valid - // * OK [UIDNEXT 57576] Predicted next UID - // 2 OK [READ-WRITE] Select completed. - try { - List responses = mConnection.executeSimpleCommand( - String.format("SELECT \"%s\"", - encodeFolderName(mName))); - /* - * If the command succeeds we expect the folder has been opened read-write - * unless we are notified otherwise in the responses. - */ - mMode = OpenMode.READ_WRITE; - - for (ImapResponse response : responses) { - if (response.mTag == null && response.get(1).equals("EXISTS")) { - mMessageCount = response.getNumber(0); - } - else if (response.mTag != null && response.size() >= 2) { - if ("[READ-ONLY]".equalsIgnoreCase(response.getString(1))) { - mMode = OpenMode.READ_ONLY; - } - else if ("[READ-WRITE]".equalsIgnoreCase(response.getString(1))) { - mMode = OpenMode.READ_WRITE; - } - } - } - - if (mMessageCount == -1) { - throw new MessagingException( - "Did not find message count during select"); - } - mExists = true; - - } catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - } - - public boolean isOpen() { - return mConnection != null; - } - - @Override - public OpenMode getMode() throws MessagingException { - return mMode; - } - - public void close(boolean expunge) { - if (!isOpen()) { - return; - } - // TODO implement expunge - mMessageCount = -1; - synchronized (this) { - releaseConnection(mConnection); - mConnection = null; - } - } - - public String getName() { - return mName; - } - - public boolean exists() throws MessagingException { - if (mExists) { - return true; - } - /* - * This method needs to operate in the unselected mode as well as the selected mode - * so we must get the connection ourselves if it's not there. We are specifically - * not calling checkOpen() since we don't care if the folder is open. - */ - ImapConnection connection = null; - synchronized(this) { - if (mConnection == null) { - connection = getConnection(); - } - else { - connection = mConnection; - } - } - try { - connection.executeSimpleCommand(String.format("STATUS \"%s\" (UIDVALIDITY)", - encodeFolderName(mName))); - mExists = true; - return true; - } - catch (MessagingException me) { - return false; - } - catch (IOException ioe) { - throw ioExceptionHandler(connection, ioe); - } - finally { - if (mConnection == null) { - releaseConnection(connection); - } - } - } - - public boolean create(FolderType type) throws MessagingException { - /* - * This method needs to operate in the unselected mode as well as the selected mode - * so we must get the connection ourselves if it's not there. We are specifically - * not calling checkOpen() since we don't care if the folder is open. - */ - ImapConnection connection = null; - synchronized(this) { - if (mConnection == null) { - connection = getConnection(); - } - else { - connection = mConnection; - } - } - try { - connection.executeSimpleCommand(String.format("CREATE \"%s\"", - encodeFolderName(mName))); - return true; - } - catch (MessagingException me) { - return false; - } - catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - finally { - if (mConnection == null) { - releaseConnection(connection); - } - } - } - - @Override - public void copyMessages(Message[] messages, Folder folder) throws MessagingException { - checkOpen(); - String[] uids = new String[messages.length]; - for (int i = 0, count = messages.length; i < count; i++) { - uids[i] = messages[i].getUid(); - } - try { - mConnection.executeSimpleCommand(String.format("UID COPY %s \"%s\"", - Utility.combine(uids, ','), - encodeFolderName(folder.getName()))); - } - catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - } - - @Override - public int getMessageCount() { - return mMessageCount; - } - - @Override - public int getUnreadMessageCount() throws MessagingException { - checkOpen(); - try { - int unreadMessageCount = 0; - List responses = mConnection.executeSimpleCommand( - String.format("STATUS \"%s\" (UNSEEN)", - encodeFolderName(mName))); - for (ImapResponse response : responses) { - if (response.mTag == null && response.get(0).equals("STATUS")) { - ImapList status = response.getList(2); - unreadMessageCount = status.getKeyedNumber("UNSEEN"); - } - } - return unreadMessageCount; - } - catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - } - - @Override - public void delete(boolean recurse) throws MessagingException { - throw new Error("ImapStore.delete() not yet implemented"); - } - - @Override - public Message getMessage(String uid) throws MessagingException { - checkOpen(); - - try { - try { - List responses = - mConnection.executeSimpleCommand(String.format("UID SEARCH UID %S", uid)); - for (ImapResponse response : responses) { - if (response.mTag == null && response.get(0).equals("SEARCH")) { - for (int i = 1, count = response.size(); i < count; i++) { - if (uid.equals(response.get(i))) { - return new ImapMessage(uid, this); - } - } - } - } - } - catch (MessagingException me) { - return null; - } - } - catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - return null; - } - - @Override - public Message[] getMessages(int start, int end, MessageRetrievalListener listener) - throws MessagingException { - if (start < 1 || end < 1 || end < start) { - throw new MessagingException( - String.format("Invalid message set %d %d", - start, end)); - } - checkOpen(); - ArrayList messages = new ArrayList(); - try { - ArrayList uids = new ArrayList(); - List responses = mConnection - .executeSimpleCommand(String.format("UID SEARCH %d:%d NOT DELETED", start, end)); - for (ImapResponse response : responses) { - if (response.get(0).equals("SEARCH")) { - for (int i = 1, count = response.size(); i < count; i++) { - uids.add(response.getString(i)); - } - } - } - for (int i = 0, count = uids.size(); i < count; i++) { - if (listener != null) { - listener.messageStarted(uids.get(i), i, count); - } - ImapMessage message = new ImapMessage(uids.get(i), this); - messages.add(message); - if (listener != null) { - listener.messageFinished(message, i, count); - } - } - } catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - return messages.toArray(new Message[] {}); - } - - public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException { - return getMessages(null, listener); - } - - public Message[] getMessages(String[] uids, MessageRetrievalListener listener) - throws MessagingException { - checkOpen(); - ArrayList messages = new ArrayList(); - try { - if (uids == null) { - List responses = mConnection - .executeSimpleCommand("UID SEARCH 1:* NOT DELETED"); - ArrayList tempUids = new ArrayList(); - for (ImapResponse response : responses) { - if (response.get(0).equals("SEARCH")) { - for (int i = 1, count = response.size(); i < count; i++) { - tempUids.add(response.getString(i)); - } - } - } - uids = tempUids.toArray(new String[] {}); - } - for (int i = 0, count = uids.length; i < count; i++) { - if (listener != null) { - listener.messageStarted(uids[i], i, count); - } - ImapMessage message = new ImapMessage(uids[i], this); - messages.add(message); - if (listener != null) { - listener.messageFinished(message, i, count); - } - } - } catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - return messages.toArray(new Message[] {}); - } - - public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener) - throws MessagingException { - if (messages == null || messages.length == 0) { - return; - } - checkOpen(); - String[] uids = new String[messages.length]; - HashMap messageMap = new HashMap(); - for (int i = 0, count = messages.length; i < count; i++) { - uids[i] = messages[i].getUid(); - messageMap.put(uids[i], messages[i]); - } - - /* - * Figure out what command we are going to run: - * Flags - UID FETCH (FLAGS) - * Envelope - UID FETCH ([FLAGS] INTERNALDATE UID RFC822.SIZE FLAGS BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc)]) - * - */ - LinkedHashSet fetchFields = new LinkedHashSet(); - fetchFields.add("UID"); - if (fp.contains(FetchProfile.Item.FLAGS)) { - fetchFields.add("FLAGS"); - } - if (fp.contains(FetchProfile.Item.ENVELOPE)) { - fetchFields.add("INTERNALDATE"); - fetchFields.add("RFC822.SIZE"); - fetchFields.add("BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc)]"); - } - if (fp.contains(FetchProfile.Item.STRUCTURE)) { - fetchFields.add("BODYSTRUCTURE"); - } - if (fp.contains(FetchProfile.Item.BODY_SANE)) { - fetchFields.add(String.format("BODY.PEEK[]<0.%d>", FETCH_BODY_SANE_SUGGESTED_SIZE)); - } - if (fp.contains(FetchProfile.Item.BODY)) { - fetchFields.add("BODY.PEEK[]"); - } - for (Object o : fp) { - if (o instanceof Part) { - Part part = (Part) o; - String partId = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA)[0]; - fetchFields.add("BODY.PEEK[" + partId + "]"); - } - } - - try { - String tag = mConnection.sendCommand(String.format("UID FETCH %s (%s)", - Utility.combine(uids, ','), - Utility.combine(fetchFields.toArray(new String[fetchFields.size()]), ' ') - ), false); - ImapResponse response; - int messageNumber = 0; - do { - response = mConnection.readResponse(); - - if (response.mTag == null && response.get(1).equals("FETCH")) { - ImapList fetchList = (ImapList)response.getKeyedValue("FETCH"); - String uid = fetchList.getKeyedString("UID"); - - Message message = messageMap.get(uid); - - if (listener != null) { - listener.messageStarted(uid, messageNumber++, messageMap.size()); - } - - if (fp.contains(FetchProfile.Item.FLAGS)) { - ImapList flags = fetchList.getKeyedList("FLAGS"); - ImapMessage imapMessage = (ImapMessage) message; - if (flags != null) { - for (int i = 0, count = flags.size(); i < count; i++) { - String flag = flags.getString(i); - if (flag.equals("\\Deleted")) { - imapMessage.setFlagInternal(Flag.DELETED, true); - } - else if (flag.equals("\\Answered")) { - imapMessage.setFlagInternal(Flag.ANSWERED, true); - } - else if (flag.equals("\\Seen")) { - imapMessage.setFlagInternal(Flag.SEEN, true); - } - else if (flag.equals("\\Flagged")) { - imapMessage.setFlagInternal(Flag.FLAGGED, true); - } - } - } - } - if (fp.contains(FetchProfile.Item.ENVELOPE)) { - Date internalDate = fetchList.getKeyedDate("INTERNALDATE"); - int size = fetchList.getKeyedNumber("RFC822.SIZE"); - InputStream headerStream = fetchList.getLiteral(fetchList.size() - 1); - - ImapMessage imapMessage = (ImapMessage) message; - - message.setInternalDate(internalDate); - imapMessage.setSize(size); - imapMessage.parse(headerStream); - } - if (fp.contains(FetchProfile.Item.STRUCTURE)) { - ImapList bs = fetchList.getKeyedList("BODYSTRUCTURE"); - if (bs != null) { - try { - parseBodyStructure(bs, message, "TEXT"); - } - catch (MessagingException e) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "Error handling message", e); - } - message.setBody(null); - } - } - } - if (fp.contains(FetchProfile.Item.BODY)) { - InputStream bodyStream = fetchList.getLiteral(fetchList.size() - 1); - ImapMessage imapMessage = (ImapMessage) message; - imapMessage.parse(bodyStream); - } - if (fp.contains(FetchProfile.Item.BODY_SANE)) { - InputStream bodyStream = fetchList.getLiteral(fetchList.size() - 1); - ImapMessage imapMessage = (ImapMessage) message; - imapMessage.parse(bodyStream); - } - for (Object o : fp) { - if (o instanceof Part) { - Part part = (Part) o; - InputStream bodyStream = fetchList.getLiteral(fetchList.size() - 1); - String contentType = part.getContentType(); - String contentTransferEncoding = part.getHeader( - MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING)[0]; - part.setBody(MimeUtility.decodeBody( - bodyStream, - contentTransferEncoding)); - } - } - - if (listener != null) { - listener.messageFinished(message, messageNumber, messageMap.size()); - } - } - - while (response.more()); - - } while (response.mTag == null); - } - catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - } - - @Override - public Flag[] getPermanentFlags() throws MessagingException { - return PERMANENT_FLAGS; - } - - /** - * Handle any untagged responses that the caller doesn't care to handle themselves. - * @param responses - */ - private void handleUntaggedResponses(List responses) { - for (ImapResponse response : responses) { - handleUntaggedResponse(response); - } - } - - /** - * Handle an untagged response that the caller doesn't care to handle themselves. - * @param response - */ - private void handleUntaggedResponse(ImapResponse response) { - if (response.mTag == null && response.get(1).equals("EXISTS")) { - mMessageCount = response.getNumber(0); - } - } - - private void parseBodyStructure(ImapList bs, Part part, String id) - throws MessagingException { - if (bs.get(0) instanceof ImapList) { - /* - * This is a multipart/* - */ - MimeMultipart mp = new MimeMultipart(); - for (int i = 0, count = bs.size(); i < count; i++) { - if (bs.get(i) instanceof ImapList) { - /* - * For each part in the message we're going to add a new BodyPart and parse - * into it. - */ - ImapBodyPart bp = new ImapBodyPart(); - if (id.equals("TEXT")) { - parseBodyStructure(bs.getList(i), bp, Integer.toString(i + 1)); - } - else { - parseBodyStructure(bs.getList(i), bp, id + "." + (i + 1)); - } - mp.addBodyPart(bp); - } - else { - /* - * We've got to the end of the children of the part, so now we can find out - * what type it is and bail out. - */ - String subType = bs.getString(i); - mp.setSubType(subType.toLowerCase()); - break; - } - } - part.setBody(mp); - } - else{ - /* - * This is a body. We need to add as much information as we can find out about - * it to the Part. - */ - - /* - body type - body subtype - body parameter parenthesized list - body id - body description - body encoding - body size - */ - - - String type = bs.getString(0); - String subType = bs.getString(1); - String mimeType = (type + "/" + subType).toLowerCase(); - - ImapList bodyParams = null; - if (bs.get(2) instanceof ImapList) { - bodyParams = bs.getList(2); - } - String encoding = bs.getString(5); - int size = bs.getNumber(6); - - if (MimeUtility.mimeTypeMatches(mimeType, "message/rfc822")) { -// A body type of type MESSAGE and subtype RFC822 -// contains, immediately after the basic fields, the -// envelope structure, body structure, and size in -// text lines of the encapsulated message. -// [MESSAGE, RFC822, [NAME, Fwd: [#HTR-517941]: update plans at 1am Friday - Memory allocation - displayware.eml], NIL, NIL, 7BIT, 5974, NIL, [INLINE, [FILENAME*0, Fwd: [#HTR-517941]: update plans at 1am Friday - Memory all, FILENAME*1, ocation - displayware.eml]], NIL] - /* - * This will be caught by fetch and handled appropriately. - */ - throw new MessagingException("BODYSTRUCTURE message/rfc822 not yet supported."); - } - - /* - * Set the content type with as much information as we know right now. - */ - String contentType = String.format("%s", mimeType); - - if (bodyParams != null) { - /* - * If there are body params we might be able to get some more information out - * of them. - */ - for (int i = 0, count = bodyParams.size(); i < count; i += 2) { - contentType += String.format(";\n %s=\"%s\"", - bodyParams.getString(i), - bodyParams.getString(i + 1)); - } - } - - part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType); - - // Extension items - ImapList bodyDisposition = null; - if (("text".equalsIgnoreCase(type)) - && (bs.size() > 8) - && (bs.get(9) instanceof ImapList)) { - bodyDisposition = bs.getList(9); - } - else if (!("text".equalsIgnoreCase(type)) - && (bs.size() > 7) - && (bs.get(8) instanceof ImapList)) { - bodyDisposition = bs.getList(8); - } - - String contentDisposition = ""; - - if (bodyDisposition != null && bodyDisposition.size() > 0) { - if (!"NIL".equalsIgnoreCase(bodyDisposition.getString(0))) { - contentDisposition = bodyDisposition.getString(0).toLowerCase(); - } - - if ((bodyDisposition.size() > 1) - && (bodyDisposition.get(1) instanceof ImapList)) { - ImapList bodyDispositionParams = bodyDisposition.getList(1); - /* - * If there is body disposition information we can pull some more information - * about the attachment out. - */ - for (int i = 0, count = bodyDispositionParams.size(); i < count; i += 2) { - contentDisposition += String.format(";\n %s=\"%s\"", - bodyDispositionParams.getString(i).toLowerCase(), - bodyDispositionParams.getString(i + 1)); - } - } - } - - if (MimeUtility.getHeaderParameter(contentDisposition, "size") == null) { - contentDisposition += String.format(";\n size=%d", size); - } - - /* - * Set the content disposition containing at least the size. Attachment - * handling code will use this down the road. - */ - part.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, contentDisposition); - - - /* - * Set the Content-Transfer-Encoding header. Attachment code will use this - * to parse the body. - */ - part.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, encoding); - - if (part instanceof ImapMessage) { - ((ImapMessage) part).setSize(size); - } - else if (part instanceof ImapBodyPart) { - ((ImapBodyPart) part).setSize(size); - } - else { - throw new MessagingException("Unknown part type " + part.toString()); - } - part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id); - } - - } - - /** - * Appends the given messages to the selected folder. This implementation also determines - * the new UID of the given message on the IMAP server and sets the Message's UID to the - * new server UID. - */ - public void appendMessages(Message[] messages) throws MessagingException { - checkOpen(); - try { - for (Message message : messages) { - CountingOutputStream out = new CountingOutputStream(); - EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(out); - message.writeTo(eolOut); - eolOut.flush(); - mConnection.sendCommand( - String.format("APPEND \"%s\" {%d}", - encodeFolderName(mName), - out.getCount()), false); - ImapResponse response; - do { - response = mConnection.readResponse(); - if (response.mCommandContinuationRequested) { - eolOut = new EOLConvertingOutputStream(mConnection.mOut); - message.writeTo(eolOut); - eolOut.write('\r'); - eolOut.write('\n'); - eolOut.flush(); - } - else if (response.mTag == null) { - handleUntaggedResponse(response); - } - while (response.more()); - } while(response.mTag == null); - - /* - * Try to find the UID of the message we just appended using the - * Message-ID header. - */ - String[] messageIdHeader = message.getHeader("Message-ID"); - if (messageIdHeader == null || messageIdHeader.length == 0) { - continue; - } - String messageId = messageIdHeader[0]; - List responses = - mConnection.executeSimpleCommand( - String.format("UID SEARCH (HEADER MESSAGE-ID %s)", messageId)); - for (ImapResponse response1 : responses) { - if (response1.mTag == null && response1.get(0).equals("SEARCH") - && response1.size() > 1) { - message.setUid(response1.getString(1)); - } - } - - } - } - catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - } - - public Message[] expunge() throws MessagingException { - checkOpen(); - try { - handleUntaggedResponses(mConnection.executeSimpleCommand("EXPUNGE")); - } catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - return null; - } - - public void setFlags(Message[] messages, Flag[] flags, boolean value) - throws MessagingException { - checkOpen(); - String[] uids = new String[messages.length]; - for (int i = 0, count = messages.length; i < count; i++) { - uids[i] = messages[i].getUid(); - } - ArrayList flagNames = new ArrayList(); - for (int i = 0, count = flags.length; i < count; i++) { - Flag flag = flags[i]; - if (flag == Flag.SEEN) { - flagNames.add("\\Seen"); - } - else if (flag == Flag.DELETED) { - flagNames.add("\\Deleted"); - } - } - try { - mConnection.executeSimpleCommand(String.format("UID STORE %s %sFLAGS.SILENT (%s)", - Utility.combine(uids, ','), - value ? "+" : "-", - Utility.combine(flagNames.toArray(new String[flagNames.size()]), ' '))); - } - catch (IOException ioe) { - throw ioExceptionHandler(mConnection, ioe); - } - } - - private void checkOpen() throws MessagingException { - if (!isOpen()) { - throw new MessagingException("Folder " + mName + " is not open."); - } - } - - private MessagingException ioExceptionHandler(ImapConnection connection, IOException ioe) - throws MessagingException { - connection.close(); - close(false); - return new MessagingException("IO Error", ioe); - } - - @Override - public boolean equals(Object o) { - if (o instanceof ImapFolder) { - return ((ImapFolder)o).mName.equals(mName); - } - return super.equals(o); - } - } - - /** - * A cacheable class that stores the details for a single IMAP connection. - */ - class ImapConnection { - private Socket mSocket; - private PeekableInputStream mIn; - private OutputStream mOut; - private ImapResponseParser mParser; - private int mNextCommandTag; - - public void open() throws IOException, MessagingException { - if (isOpen()) { - return; - } - - mNextCommandTag = 1; - - try { - SocketAddress socketAddress = new InetSocketAddress(mHost, mPort); - if (mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED || - mConnectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL) { - SSLContext sslContext = SSLContext.getInstance("TLS"); - final boolean secure = mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED; - sslContext.init(null, new TrustManager[] { - TrustManagerFactory.get(mHost, secure) - }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(); - mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); - } else { - mSocket = new Socket(); - mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); - } - - mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT); - - mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(), - 1024)); - mParser = new ImapResponseParser(mIn); - mOut = mSocket.getOutputStream(); - - // BANNER - mParser.readResponse(); - - if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL - || mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { - // CAPABILITY - List responses = executeSimpleCommand("CAPABILITY"); - if (responses.size() != 2) { - throw new MessagingException("Invalid CAPABILITY response received"); - } - if (responses.get(0).contains("STARTTLS")) { - // STARTTLS - executeSimpleCommand("STARTTLS"); - - SSLContext sslContext = SSLContext.getInstance("TLS"); - boolean secure = mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED; - sslContext.init(null, new TrustManager[] { - TrustManagerFactory.get(mHost, secure) - }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(mSocket, mHost, mPort, - true); - mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT); - mIn = new PeekableInputStream(new BufferedInputStream(mSocket - .getInputStream(), 1024)); - mParser = new ImapResponseParser(mIn); - mOut = mSocket.getOutputStream(); - } else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { - throw new MessagingException("TLS not supported but required"); - } - } - - mOut = new BufferedOutputStream(mOut); - - try { - // TODO eventually we need to add additional authentication - // options such as SASL - executeSimpleCommand("LOGIN " + mUsername + " " + mPassword, true); - } catch (ImapException ie) { - throw new AuthenticationFailedException(ie.getAlertText(), ie); - - } catch (MessagingException me) { - throw new AuthenticationFailedException(null, me); - } - } catch (SSLException e) { - throw new CertificateValidationException(e.getMessage(), e); - } catch (GeneralSecurityException gse) { - throw new MessagingException( - "Unable to open connection to IMAP server due to security error.", gse); - } - } - - public boolean isOpen() { - return (mIn != null && mOut != null && mSocket != null && mSocket.isConnected() && !mSocket - .isClosed()); - } - - public void close() { -// if (isOpen()) { -// try { -// executeSimpleCommand("LOGOUT"); -// } catch (Exception e) { -// -// } -// } - try { - mIn.close(); - } catch (Exception e) { - - } - try { - mOut.close(); - } catch (Exception e) { - - } - try { - mSocket.close(); - } catch (Exception e) { - - } - mIn = null; - mOut = null; - mSocket = null; - } - - public ImapResponse readResponse() throws IOException, MessagingException { - return mParser.readResponse(); - } - - public String sendCommand(String command, boolean sensitive) - throws MessagingException, IOException { - open(); - String tag = Integer.toString(mNextCommandTag++); - String commandToSend = tag + " " + command; - mOut.write(commandToSend.getBytes()); - mOut.write('\r'); - mOut.write('\n'); - mOut.flush(); - if (Config.LOGD) { - if (k9.DEBUG) { - if (sensitive && !k9.DEBUG_SENSITIVE) { - Log.d(k9.LOG_TAG, ">>> " - + "[Command Hidden, Enable Sensitive Debug Logging To Show]"); - } else { - Log.d(k9.LOG_TAG, ">>> " + commandToSend); - } - } - } - return tag; - } - - public List executeSimpleCommand(String command) throws IOException, - ImapException, MessagingException { - return executeSimpleCommand(command, false); - } - - public List executeSimpleCommand(String command, boolean sensitive) - throws IOException, ImapException, MessagingException { - String tag = sendCommand(command, sensitive); - ArrayList responses = new ArrayList(); - ImapResponse response; - do { - response = mParser.readResponse(); - responses.add(response); - } while (response.mTag == null); - if (response.size() < 1 || !response.get(0).equals("OK")) { - throw new ImapException(response.toString(), response.getAlertText()); - } - return responses; - } - } - - class ImapMessage extends MimeMessage { - ImapMessage(String uid, Folder folder) throws MessagingException { - this.mUid = uid; - this.mFolder = folder; - } - - public void setSize(int size) { - this.mSize = size; - } - - public void parse(InputStream in) throws IOException, MessagingException { - super.parse(in); - } - - public void setFlagInternal(Flag flag, boolean set) throws MessagingException { - super.setFlag(flag, set); - } - - @Override - public void setFlag(Flag flag, boolean set) throws MessagingException { - super.setFlag(flag, set); - mFolder.setFlags(new Message[] { this }, new Flag[] { flag }, set); - } - } - - class ImapBodyPart extends MimeBodyPart { - public ImapBodyPart() throws MessagingException { - super(); - } - - public void setSize(int size) { - this.mSize = size; - } - } - - class ImapException extends MessagingException { - String mAlertText; - - public ImapException(String message, String alertText, Throwable throwable) { - super(message, throwable); - this.mAlertText = alertText; - } - - public ImapException(String message, String alertText) { - super(message); - this.mAlertText = alertText; - } - - public String getAlertText() { - return mAlertText; - } - - public void setAlertText(String alertText) { - mAlertText = alertText; - } - } -} diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java deleted file mode 100644 index d97f0b293..000000000 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ /dev/null @@ -1,1187 +0,0 @@ - -package com.fsck.k9.mail.store; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Date; -import java.util.UUID; - -import org.apache.commons.io.IOUtils; - -import android.app.Application; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.Utility; -import com.fsck.k9.codec.binary.Base64OutputStream; -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.Body; -import com.fsck.k9.mail.FetchProfile; -import com.fsck.k9.mail.Flag; -import com.fsck.k9.mail.Folder; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessageRetrievalListener; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Part; -import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.internet.MimeBodyPart; -import com.fsck.k9.mail.internet.MimeHeader; -import com.fsck.k9.mail.internet.MimeMessage; -import com.fsck.k9.mail.internet.MimeMultipart; -import com.fsck.k9.mail.internet.MimeUtility; -import com.fsck.k9.mail.internet.TextBody; -import com.fsck.k9.provider.AttachmentProvider; - -/** - *
- * Implements a SQLite database backed local store for Messages.
- * 
- */ -public class LocalStore extends Store { - private static final int DB_VERSION = 18; - private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN }; - - private String mPath; - private SQLiteDatabase mDb; - private File mAttachmentsDir; - private Application mApplication; - - /** - * @param uri local://localhost/path/to/database/uuid.db - */ - public LocalStore(String _uri, Application application) throws MessagingException { - mApplication = application; - URI uri = null; - try { - uri = new URI(_uri); - } catch (Exception e) { - throw new MessagingException("Invalid uri for LocalStore"); - } - if (!uri.getScheme().equals("local")) { - throw new MessagingException("Invalid scheme"); - } - mPath = uri.getPath(); - - File parentDir = new File(mPath).getParentFile(); - if (!parentDir.exists()) { - parentDir.mkdirs(); - } - mDb = SQLiteDatabase.openOrCreateDatabase(mPath, null); - if (mDb.getVersion() != DB_VERSION) { - doDbUpgrade(mDb); - } - - - mAttachmentsDir = new File(mPath + "_att"); - if (!mAttachmentsDir.exists()) { - mAttachmentsDir.mkdirs(); - } - } - - - private void doDbUpgrade ( SQLiteDatabase mDb) { - - if (mDb.getVersion() < 18) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, String.format("Upgrading database from %d to %d", mDb - .getVersion(), 18)); - } - mDb.execSQL("DROP TABLE IF EXISTS folders"); - mDb.execSQL("CREATE TABLE folders (id INTEGER PRIMARY KEY, name TEXT, " - + "last_updated INTEGER, unread_count INTEGER, visible_limit INTEGER)"); - - mDb.execSQL("DROP TABLE IF EXISTS messages"); - mDb.execSQL("CREATE TABLE messages (id INTEGER PRIMARY KEY, folder_id INTEGER, uid TEXT, subject TEXT, " - + "date INTEGER, flags TEXT, sender_list TEXT, to_list TEXT, cc_list TEXT, bcc_list TEXT, reply_to_list TEXT, " - + "html_content TEXT, text_content TEXT, attachment_count INTEGER, internal_date INTEGER)"); - - mDb.execSQL("DROP TABLE IF EXISTS attachments"); - mDb.execSQL("CREATE TABLE attachments (id INTEGER PRIMARY KEY, message_id INTEGER," - + "store_data TEXT, content_uri TEXT, size INTEGER, name TEXT," - + "mime_type TEXT)"); - - mDb.execSQL("DROP TABLE IF EXISTS pending_commands"); - mDb.execSQL("CREATE TABLE pending_commands " + - "(id INTEGER PRIMARY KEY, command TEXT, arguments TEXT)"); - - mDb.execSQL("DROP TRIGGER IF EXISTS delete_folder"); - mDb.execSQL("CREATE TRIGGER delete_folder BEFORE DELETE ON folders BEGIN DELETE FROM messages WHERE old.id = folder_id; END;"); - - mDb.execSQL("DROP TRIGGER IF EXISTS delete_message"); - mDb.execSQL("CREATE TRIGGER delete_message BEFORE DELETE ON messages BEGIN DELETE FROM attachments WHERE old.id = message_id; END;"); - mDb.setVersion(18); - } - if (mDb.getVersion() != DB_VERSION) { - throw new Error("Database upgrade failed!"); - } - } - - @Override - public Folder getFolder(String name) throws MessagingException { - return new LocalFolder(name); - } - - // TODO this takes about 260-300ms, seems slow. - @Override - public Folder[] getPersonalNamespaces() throws MessagingException { - ArrayList folders = new ArrayList(); - Cursor cursor = null; - try { - cursor = mDb.rawQuery("SELECT name FROM folders", null); - while (cursor.moveToNext()) { - folders.add(new LocalFolder(cursor.getString(0))); - } - } - finally { - if (cursor != null) { - cursor.close(); - } - } - return folders.toArray(new Folder[] {}); - } - - @Override - public void checkSettings() throws MessagingException { - } - - /** - * Delete the entire Store and it's backing database. - */ - public void delete() { - try { - mDb.close(); - } catch (Exception e) { - - } - try{ - File[] attachments = mAttachmentsDir.listFiles(); - for (File attachment : attachments) { - if (attachment.exists()) { - attachment.delete(); - } - } - if (mAttachmentsDir.exists()) { - mAttachmentsDir.delete(); - } - } - catch (Exception e) { - } - try { - new File(mPath).delete(); - } - catch (Exception e) { - - } - } - - /** - * Deletes all cached attachments for the entire store. - */ - public void pruneCachedAttachments() throws MessagingException { - File[] files = mAttachmentsDir.listFiles(); - for (File file : files) { - if (file.exists()) { - try { - Cursor cursor = null; - try { - cursor = mDb.query( - "attachments", - new String[] { "store_data" }, - "id = ?", - new String[] { file.getName() }, - null, - null, - null); - if (cursor.moveToNext()) { - if (cursor.getString(0) == null) { - /* - * If the attachment has no store data it is not recoverable, so - * we won't delete it. - */ - continue; - } - } - } - finally { - if (cursor != null) { - cursor.close(); - } - } - ContentValues cv = new ContentValues(); - cv.putNull("content_uri"); - mDb.update("attachments", cv, "id = ?", new String[] { file.getName() }); - } - catch (Exception e) { - /* - * If the row has gone away before we got to mark it not-downloaded that's - * okay. - */ - } - if (!file.delete()) { - file.deleteOnExit(); - } - } - } - } - - public void resetVisibleLimits() { - ContentValues cv = new ContentValues(); - cv.put("visible_limit", Integer.toString(k9.DEFAULT_VISIBLE_LIMIT)); - mDb.update("folders", cv, null, null); - } - - public ArrayList getPendingCommands() { - Cursor cursor = null; - try { - cursor = mDb.query("pending_commands", - new String[] { "id", "command", "arguments" }, - null, - null, - null, - null, - "id ASC"); - ArrayList commands = new ArrayList(); - while (cursor.moveToNext()) { - PendingCommand command = new PendingCommand(); - command.mId = cursor.getLong(0); - command.command = cursor.getString(1); - String arguments = cursor.getString(2); - command.arguments = arguments.split(","); - for (int i = 0; i < command.arguments.length; i++) { - command.arguments[i] = Utility.fastUrlDecode(command.arguments[i]); - } - commands.add(command); - } - return commands; - } - finally { - if (cursor != null) { - cursor.close(); - } - } - } - - public void addPendingCommand(PendingCommand command) { - try { - for (int i = 0; i < command.arguments.length; i++) { - command.arguments[i] = URLEncoder.encode(command.arguments[i], "UTF-8"); - } - ContentValues cv = new ContentValues(); - cv.put("command", command.command); - cv.put("arguments", Utility.combine(command.arguments, ',')); - mDb.insert("pending_commands", "command", cv); - } - catch (UnsupportedEncodingException usee) { - throw new Error("Aparently UTF-8 has been lost to the annals of history."); - } - } - - public void removePendingCommand(PendingCommand command) { - mDb.delete("pending_commands", "id = ?", new String[] { Long.toString(command.mId) }); - } - - public static class PendingCommand { - private long mId; - public String command; - public String[] arguments; - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(command); - sb.append("\n"); - for (String argument : arguments) { - sb.append(" "); - sb.append(argument); - sb.append("\n"); - } - return sb.toString(); - } - } - - public class LocalFolder extends Folder { - private String mName; - private long mFolderId = -1; - private int mUnreadMessageCount = -1; - private int mVisibleLimit = -1; - - public LocalFolder(String name) { - this.mName = name; - } - - public long getId() { - return mFolderId; - } - - @Override - public void open(OpenMode mode) throws MessagingException { - if (isOpen()) { - return; - } - if (!exists()) { - create(FolderType.HOLDS_MESSAGES); - } - Cursor cursor = null; - try { - cursor = mDb.rawQuery("SELECT id, unread_count, visible_limit FROM folders " - + "where folders.name = ?", - new String[] { - mName - }); - cursor.moveToFirst(); - mFolderId = cursor.getInt(0); - mUnreadMessageCount = cursor.getInt(1); - mVisibleLimit = cursor.getInt(2); - } - finally { - if (cursor != null) { - cursor.close(); - } - } - } - - @Override - public boolean isOpen() { - return mFolderId != -1; - } - - @Override - public OpenMode getMode() throws MessagingException { - return OpenMode.READ_WRITE; - } - - @Override - public String getName() { - return mName; - } - - @Override - public boolean exists() throws MessagingException { - return Utility.arrayContains(getPersonalNamespaces(), this); - } - - @Override - public boolean create(FolderType type) throws MessagingException { - if (exists()) { - throw new MessagingException("Folder " + mName + " already exists."); - } - mDb.execSQL("INSERT INTO folders (name, visible_limit) VALUES (?, ?)", new Object[] { - mName, - k9.DEFAULT_VISIBLE_LIMIT - }); - return true; - } - - @Override - public void close(boolean expunge) throws MessagingException { - if (expunge) { - expunge(); - } - mFolderId = -1; - } - - @Override - public int getMessageCount() throws MessagingException { - open(OpenMode.READ_WRITE); - Cursor cursor = null; - try { - cursor = mDb.rawQuery("SELECT COUNT(*) FROM messages WHERE messages.folder_id = ?", - new String[] { - Long.toString(mFolderId) - }); - cursor.moveToFirst(); - int messageCount = cursor.getInt(0); - return messageCount; - } - finally { - if (cursor != null) { - cursor.close(); - } - } - } - - @Override - public int getUnreadMessageCount() throws MessagingException { - open(OpenMode.READ_WRITE); - return mUnreadMessageCount; - } - - - public void setUnreadMessageCount(int unreadMessageCount) throws MessagingException { - open(OpenMode.READ_WRITE); - mUnreadMessageCount = Math.max(0, unreadMessageCount); - mDb.execSQL("UPDATE folders SET unread_count = ? WHERE id = ?", - new Object[] { mUnreadMessageCount, mFolderId }); - } - - public int getVisibleLimit() throws MessagingException { - open(OpenMode.READ_WRITE); - return mVisibleLimit; - } - - - public void setVisibleLimit(int visibleLimit) throws MessagingException { - open(OpenMode.READ_WRITE); - mVisibleLimit = visibleLimit; - mDb.execSQL("UPDATE folders SET visible_limit = ? WHERE id = ?", - new Object[] { mVisibleLimit, mFolderId }); - } - - - @Override - public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener) - throws MessagingException { - open(OpenMode.READ_WRITE); - if (fp.contains(FetchProfile.Item.BODY)) { - for (Message message : messages) { - LocalMessage localMessage = (LocalMessage)message; - Cursor cursor = null; - localMessage.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "multipart/mixed"); - MimeMultipart mp = new MimeMultipart(); - mp.setSubType("mixed"); - localMessage.setBody(mp); - try { - cursor = mDb.rawQuery("SELECT html_content, text_content FROM messages " - + "WHERE id = ?", - new String[] { Long.toString(localMessage.mId) }); - cursor.moveToNext(); - String htmlContent = cursor.getString(0); - String textContent = cursor.getString(1); - - if (htmlContent != null) { - TextBody body = new TextBody(htmlContent); - MimeBodyPart bp = new MimeBodyPart(body, "text/html"); - mp.addBodyPart(bp); - } - - if (textContent != null) { - TextBody body = new TextBody(textContent); - MimeBodyPart bp = new MimeBodyPart(body, "text/plain"); - mp.addBodyPart(bp); - } - } - finally { - if (cursor != null) { - cursor.close(); - } - } - - try { - cursor = mDb.query( - "attachments", - new String[] { - "id", - "size", - "name", - "mime_type", - "store_data", - "content_uri" }, - "message_id = ?", - new String[] { Long.toString(localMessage.mId) }, - null, - null, - null); - - while (cursor.moveToNext()) { - long id = cursor.getLong(0); - int size = cursor.getInt(1); - String name = cursor.getString(2); - String type = cursor.getString(3); - String storeData = cursor.getString(4); - String contentUri = cursor.getString(5); - Body body = null; - if (contentUri != null) { - body = new LocalAttachmentBody(Uri.parse(contentUri), mApplication); - } - MimeBodyPart bp = new LocalAttachmentBodyPart(body, id); - bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE, - String.format("%s;\n name=\"%s\"", - type, - name)); - bp.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); - bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, - String.format("attachment;\n filename=\"%s\";\n size=%d", - name, - size)); - - /* - * HEADER_ANDROID_ATTACHMENT_STORE_DATA is a custom header we add to that - * we can later pull the attachment from the remote store if neccesary. - */ - bp.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, storeData); - - mp.addBodyPart(bp); - } - } - finally { - if (cursor != null) { - cursor.close(); - } - } - } - } - } - - private void populateMessageFromGetMessageCursor(LocalMessage message, Cursor cursor) - throws MessagingException{ - message.setSubject(cursor.getString(0) == null ? "" : cursor.getString(0)); - Address[] from = Address.unpack(cursor.getString(1)); - if (from.length > 0) { - message.setFrom(from[0]); - } - message.setSentDate(new Date(cursor.getLong(2))); - message.setUid(cursor.getString(3)); - String flagList = cursor.getString(4); - if (flagList != null && flagList.length() > 0) { - String[] flags = flagList.split(","); - try { - for (String flag : flags) { - message.setFlagInternal(Flag.valueOf(flag.toUpperCase()), true); - } - } catch (Exception e) { - } - } - message.mId = cursor.getLong(5); - message.setRecipients(RecipientType.TO, Address.unpack(cursor.getString(6))); - message.setRecipients(RecipientType.CC, Address.unpack(cursor.getString(7))); - message.setRecipients(RecipientType.BCC, Address.unpack(cursor.getString(8))); - message.setReplyTo(Address.unpack(cursor.getString(9))); - message.mAttachmentCount = cursor.getInt(10); - message.setInternalDate(new Date(cursor.getLong(11))); - } - - @Override - public Message[] getMessages(int start, int end, MessageRetrievalListener listener) - throws MessagingException { - open(OpenMode.READ_WRITE); - throw new MessagingException( - "LocalStore.getMessages(int, int, MessageRetrievalListener) not yet implemented"); - } - - @Override - public Message getMessage(String uid) throws MessagingException { - open(OpenMode.READ_WRITE); - LocalMessage message = new LocalMessage(uid, this); - Cursor cursor = null; - try { - cursor = mDb.rawQuery( - "SELECT subject, sender_list, date, uid, flags, id, to_list, cc_list, " - + "bcc_list, reply_to_list, attachment_count, internal_date " - + "FROM messages " + "WHERE uid = ? " + "AND folder_id = ?", - new String[] { - message.getUid(), Long.toString(mFolderId) - }); - if (!cursor.moveToNext()) { - return null; - } - populateMessageFromGetMessageCursor(message, cursor); - } - finally { - if (cursor != null) { - cursor.close(); - } - } - return message; - } - - @Override - public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException { - open(OpenMode.READ_WRITE); - ArrayList messages = new ArrayList(); - Cursor cursor = null; - try { - cursor = mDb.rawQuery( - "SELECT subject, sender_list, date, uid, flags, id, to_list, cc_list, " - + "bcc_list, reply_to_list, attachment_count, internal_date " - + "FROM messages " + "WHERE folder_id = ?", new String[] { - Long.toString(mFolderId) - }); - - while (cursor.moveToNext()) { - LocalMessage message = new LocalMessage(null, this); - populateMessageFromGetMessageCursor(message, cursor); - messages.add(message); - } - } - finally { - if (cursor != null) { - cursor.close(); - } - } - - return messages.toArray(new Message[] {}); - } - - @Override - public Message[] getMessages(String[] uids, MessageRetrievalListener listener) - throws MessagingException { - open(OpenMode.READ_WRITE); - if (uids == null) { - return getMessages(listener); - } - ArrayList messages = new ArrayList(); - for (String uid : uids) { - messages.add(getMessage(uid)); - } - return messages.toArray(new Message[] {}); - } - - @Override - public void copyMessages(Message[] msgs, Folder folder) throws MessagingException { - if (!(folder instanceof LocalFolder)) { - throw new MessagingException("copyMessages called with incorrect Folder"); - } - ((LocalFolder) folder).appendMessages(msgs, true); - } - - /** - * The method differs slightly from the contract; If an incoming message already has a uid - * assigned and it matches the uid of an existing message then this message will replace the - * old message. It is implemented as a delete/insert. This functionality is used in saving - * of drafts and re-synchronization of updated server messages. - */ - @Override - public void appendMessages(Message[] messages) throws MessagingException { - appendMessages(messages, false); - } - - /** - * The method differs slightly from the contract; If an incoming message already has a uid - * assigned and it matches the uid of an existing message then this message will replace the - * old message. It is implemented as a delete/insert. This functionality is used in saving - * of drafts and re-synchronization of updated server messages. - */ - public void appendMessages(Message[] messages, boolean copy) throws MessagingException { - open(OpenMode.READ_WRITE); - for (Message message : messages) { - if (!(message instanceof MimeMessage)) { - throw new Error("LocalStore can only store Messages that extend MimeMessage"); - } - - String uid = message.getUid(); - if (uid == null) { - message.setUid("Local" + UUID.randomUUID().toString()); - } - else { - /* - * The message may already exist in this Folder, so delete it first. - */ - deleteAttachments(message.getUid()); - mDb.execSQL("DELETE FROM messages WHERE folder_id = ? AND uid = ?", - new Object[] { mFolderId, message.getUid() }); - } - - ArrayList viewables = new ArrayList(); - ArrayList attachments = new ArrayList(); - MimeUtility.collectParts(message, viewables, attachments); - - StringBuffer sbHtml = new StringBuffer(); - StringBuffer sbText = new StringBuffer(); - for (Part viewable : viewables) { - try { - String text = MimeUtility.getTextFromPart(viewable); - /* - * Anything with MIME type text/html will be stored as such. Anything - * else will be stored as text/plain. - */ - if (viewable.getMimeType().equalsIgnoreCase("text/html")) { - sbHtml.append(text); - } - else { - sbText.append(text); - } - } catch (Exception e) { - throw new MessagingException("Unable to get text for message part", e); - } - } - - try { - ContentValues cv = new ContentValues(); - cv.put("uid", message.getUid()); - cv.put("subject", message.getSubject()); - cv.put("sender_list", Address.pack(message.getFrom())); - cv.put("date", message.getSentDate() == null - ? System.currentTimeMillis() : message.getSentDate().getTime()); - cv.put("flags", Utility.combine(message.getFlags(), ',').toUpperCase()); - cv.put("folder_id", mFolderId); - cv.put("to_list", Address.pack(message.getRecipients(RecipientType.TO))); - cv.put("cc_list", Address.pack(message.getRecipients(RecipientType.CC))); - cv.put("bcc_list", Address.pack(message.getRecipients(RecipientType.BCC))); - cv.put("html_content", sbHtml.length() > 0 ? sbHtml.toString() : null); - cv.put("text_content", sbText.length() > 0 ? sbText.toString() : null); - cv.put("reply_to_list", Address.pack(message.getReplyTo())); - cv.put("attachment_count", attachments.size()); - cv.put("internal_date", message.getInternalDate() == null - ? System.currentTimeMillis() : message.getInternalDate().getTime()); - long messageId = mDb.insert("messages", "uid", cv); - for (Part attachment : attachments) { - saveAttachment(messageId, attachment, copy); - } - } catch (Exception e) { - throw new MessagingException("Error appending message", e); - } - } - } - - /** - * Update the given message in the LocalStore without first deleting the existing - * message (contrast with appendMessages). This method is used to store changes - * to the given message while updating attachments and not removing existing - * attachment data. - * TODO In the future this method should be combined with appendMessages since the Message - * contains enough data to decide what to do. - * @param message - * @throws MessagingException - */ - public void updateMessage(LocalMessage message) throws MessagingException { - open(OpenMode.READ_WRITE); - ArrayList viewables = new ArrayList(); - ArrayList attachments = new ArrayList(); - MimeUtility.collectParts(message, viewables, attachments); - - StringBuffer sbHtml = new StringBuffer(); - StringBuffer sbText = new StringBuffer(); - for (int i = 0, count = viewables.size(); i < count; i++) { - Part viewable = viewables.get(i); - try { - String text = MimeUtility.getTextFromPart(viewable); - /* - * Anything with MIME type text/html will be stored as such. Anything - * else will be stored as text/plain. - */ - if (viewable.getMimeType().equalsIgnoreCase("text/html")) { - sbHtml.append(text); - } - else { - sbText.append(text); - } - } catch (Exception e) { - throw new MessagingException("Unable to get text for message part", e); - } - } - - try { - mDb.execSQL("UPDATE messages SET " - + "uid = ?, subject = ?, sender_list = ?, date = ?, flags = ?, " - + "folder_id = ?, to_list = ?, cc_list = ?, bcc_list = ?, " - + "html_content = ?, text_content = ?, reply_to_list = ?, " - + "attachment_count = ? WHERE id = ?", - new Object[] { - message.getUid(), - message.getSubject(), - Address.pack(message.getFrom()), - message.getSentDate() == null ? System - .currentTimeMillis() : message.getSentDate() - .getTime(), - Utility.combine(message.getFlags(), ',').toUpperCase(), - mFolderId, - Address.pack(message - .getRecipients(RecipientType.TO)), - Address.pack(message - .getRecipients(RecipientType.CC)), - Address.pack(message - .getRecipients(RecipientType.BCC)), - sbHtml.length() > 0 ? sbHtml.toString() : null, - sbText.length() > 0 ? sbText.toString() : null, - Address.pack(message.getReplyTo()), - attachments.size(), - message.mId - }); - - for (int i = 0, count = attachments.size(); i < count; i++) { - Part attachment = attachments.get(i); - saveAttachment(message.mId, attachment, false); - } - } catch (Exception e) { - throw new MessagingException("Error appending message", e); - } - } - - /** - * @param messageId - * @param attachment - * @param attachmentId -1 to create a new attachment or >= 0 to update an existing - * @throws IOException - * @throws MessagingException - */ - private void saveAttachment(long messageId, Part attachment, boolean saveAsNew) - throws IOException, MessagingException { - long attachmentId = -1; - Uri contentUri = null; - int size = -1; - File tempAttachmentFile = null; - - if ((!saveAsNew) && (attachment instanceof LocalAttachmentBodyPart)) { - attachmentId = ((LocalAttachmentBodyPart) attachment).getAttachmentId(); - } - - if (attachment.getBody() != null) { - Body body = attachment.getBody(); - if (body instanceof LocalAttachmentBody) { - contentUri = ((LocalAttachmentBody) body).getContentUri(); - } - else { - /* - * If the attachment has a body we're expected to save it into the local store - * so we copy the data into a cached attachment file. - */ - InputStream in = attachment.getBody().getInputStream(); - tempAttachmentFile = File.createTempFile("att", null, mAttachmentsDir); - FileOutputStream out = new FileOutputStream(tempAttachmentFile); - size = IOUtils.copy(in, out); - in.close(); - out.close(); - } - } - - if (size == -1) { - /* - * If the attachment is not yet downloaded see if we can pull a size - * off the Content-Disposition. - */ - String disposition = attachment.getDisposition(); - if (disposition != null) { - String s = MimeUtility.getHeaderParameter(disposition, "size"); - if (s != null) { - size = Integer.parseInt(s); - } - } - } - if (size == -1) { - size = 0; - } - - String storeData = - Utility.combine(attachment.getHeader( - MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA), ','); - - String name = MimeUtility.getHeaderParameter(attachment.getContentType(), "name"); - - if (attachmentId == -1) { - ContentValues cv = new ContentValues(); - cv.put("message_id", messageId); - cv.put("content_uri", contentUri != null ? contentUri.toString() : null); - cv.put("store_data", storeData); - cv.put("size", size); - cv.put("name", name); - cv.put("mime_type", attachment.getMimeType()); - - attachmentId = mDb.insert("attachments", "message_id", cv); - } - else { - ContentValues cv = new ContentValues(); - cv.put("content_uri", contentUri != null ? contentUri.toString() : null); - cv.put("size", size); - mDb.update( - "attachments", - cv, - "id = ?", - new String[] { Long.toString(attachmentId) }); - } - - if (tempAttachmentFile != null) { - File attachmentFile = new File(mAttachmentsDir, Long.toString(attachmentId)); - tempAttachmentFile.renameTo(attachmentFile); - contentUri = AttachmentProvider.getAttachmentUri( - new File(mPath).getName(), - attachmentId); - attachment.setBody(new LocalAttachmentBody(contentUri, mApplication)); - ContentValues cv = new ContentValues(); - cv.put("content_uri", contentUri != null ? contentUri.toString() : null); - mDb.update( - "attachments", - cv, - "id = ?", - new String[] { Long.toString(attachmentId) }); - } - - if (attachment instanceof LocalAttachmentBodyPart) { - ((LocalAttachmentBodyPart) attachment).setAttachmentId(attachmentId); - } - } - - /** - * Changes the stored uid of the given message (using it's internal id as a key) to - * the uid in the message. - * @param message - */ - public void changeUid(LocalMessage message) throws MessagingException { - open(OpenMode.READ_WRITE); - ContentValues cv = new ContentValues(); - cv.put("uid", message.getUid()); - mDb.update("messages", cv, "id = ?", new String[] { Long.toString(message.mId) }); - } - - @Override - public void setFlags(Message[] messages, Flag[] flags, boolean value) - throws MessagingException { - open(OpenMode.READ_WRITE); - for (Message message : messages) { - message.setFlags(flags, value); - } - } - - @Override - public Message[] expunge() throws MessagingException { - open(OpenMode.READ_WRITE); - ArrayList expungedMessages = new ArrayList(); - /* - * epunge() doesn't do anything because deleted messages are saved for their uids - * and really, really deleted messages are "Destroyed" and removed immediately. - */ - return expungedMessages.toArray(new Message[] {}); - } - - @Override - public void delete(boolean recurse) throws MessagingException { - // We need to open the folder first to make sure we've got it's id - open(OpenMode.READ_ONLY); - Message[] messages = getMessages(null); - for (Message message : messages) { - deleteAttachments(message.getUid()); - } - mDb.execSQL("DELETE FROM folders WHERE id = ?", new Object[] { - Long.toString(mFolderId), - }); - } - - @Override - public boolean equals(Object o) { - if (o instanceof LocalFolder) { - return ((LocalFolder)o).mName.equals(mName); - } - return super.equals(o); - } - - @Override - public Flag[] getPermanentFlags() throws MessagingException { - return PERMANENT_FLAGS; - } - - private void deleteAttachments(String uid) throws MessagingException { - open(OpenMode.READ_WRITE); - Cursor messagesCursor = null; - try { - messagesCursor = mDb.query( - "messages", - new String[] { "id" }, - "folder_id = ? AND uid = ?", - new String[] { Long.toString(mFolderId), uid }, - null, - null, - null); - while (messagesCursor.moveToNext()) { - long messageId = messagesCursor.getLong(0); - Cursor attachmentsCursor = null; - try { - attachmentsCursor = mDb.query( - "attachments", - new String[] { "id" }, - "message_id = ?", - new String[] { Long.toString(messageId) }, - null, - null, - null); - while (attachmentsCursor.moveToNext()) { - long attachmentId = attachmentsCursor.getLong(0); - try{ - File file = new File(mAttachmentsDir, Long.toString(attachmentId)); - if (file.exists()) { - file.delete(); - } - } - catch (Exception e) { - - } - } - } - finally { - if (attachmentsCursor != null) { - attachmentsCursor.close(); - } - } - } - } - finally { - if (messagesCursor != null) { - messagesCursor.close(); - } - } - } - } - - public class LocalMessage extends MimeMessage { - private long mId; - private int mAttachmentCount; - - LocalMessage(String uid, Folder folder) throws MessagingException { - this.mUid = uid; - this.mFolder = folder; - } - - public int getAttachmentCount() { - return mAttachmentCount; - } - - public void parse(InputStream in) throws IOException, MessagingException { - super.parse(in); - } - - public void setFlagInternal(Flag flag, boolean set) throws MessagingException { - super.setFlag(flag, set); - } - - public long getId() { - return mId; - } - - public void setFlag(Flag flag, boolean set) throws MessagingException { - if (flag == Flag.DELETED && set) { - /* - * If a message is being marked as deleted we want to clear out it's content - * and attachments as well. Delete will not actually remove the row since we need - * to retain the uid for synchronization purposes. - */ - - /* - * Delete all of the messages' content to save space. - */ - mDb.execSQL( - "UPDATE messages SET " + - "subject = NULL, " + - "sender_list = NULL, " + - "date = NULL, " + - "to_list = NULL, " + - "cc_list = NULL, " + - "bcc_list = NULL, " + - "html_content = NULL, " + - "text_content = NULL, " + - "reply_to_list = NULL " + - "WHERE id = ?", - new Object[] { - mId - }); - - ((LocalFolder) mFolder).deleteAttachments(getUid()); - - /* - * Delete all of the messages' attachments to save space. - */ - mDb.execSQL("DELETE FROM attachments WHERE id = ?", - new Object[] { - mId - }); - } - else if (flag == Flag.X_DESTROYED && set) { - ((LocalFolder) mFolder).deleteAttachments(getUid()); - mDb.execSQL("DELETE FROM messages WHERE id = ?", - new Object[] { mId }); - } - - /* - * Update the unread count on the folder. - */ - try { - if (flag == Flag.DELETED || flag == Flag.X_DESTROYED || flag == Flag.SEEN) { - LocalFolder folder = (LocalFolder)mFolder; - if (set && !isSet(Flag.SEEN)) { - folder.setUnreadMessageCount(folder.getUnreadMessageCount() - 1); - } - else if (!set && isSet(Flag.SEEN)) { - folder.setUnreadMessageCount(folder.getUnreadMessageCount() + 1); - } - } - } - catch (MessagingException me) { - Log.e(k9.LOG_TAG, "Unable to update LocalStore unread message count", - me); - throw new RuntimeException(me); - } - - super.setFlag(flag, set); - /* - * Set the flags on the message. - */ - mDb.execSQL("UPDATE messages " + "SET flags = ? " + "WHERE id = ?", new Object[] { - Utility.combine(getFlags(), ',').toUpperCase(), mId - }); - } - } - - public class LocalAttachmentBodyPart extends MimeBodyPart { - private long mAttachmentId = -1; - - public LocalAttachmentBodyPart(Body body, long attachmentId) throws MessagingException { - super(body); - mAttachmentId = attachmentId; - } - - /** - * Returns the local attachment id of this body, or -1 if it is not stored. - * @return - */ - public long getAttachmentId() { - return mAttachmentId; - } - - public void setAttachmentId(long attachmentId) { - mAttachmentId = attachmentId; - } - - public String toString() { - return "" + mAttachmentId; - } - } - - public static class LocalAttachmentBody implements Body { - private Application mApplication; - private Uri mUri; - - public LocalAttachmentBody(Uri uri, Application application) { - mApplication = application; - mUri = uri; - } - - public InputStream getInputStream() throws MessagingException { - try { - return mApplication.getContentResolver().openInputStream(mUri); - } - catch (FileNotFoundException fnfe) { - /* - * Since it's completely normal for us to try to serve up attachments that - * have been blown away, we just return an empty stream. - */ - return new ByteArrayInputStream(new byte[0]); - } - catch (IOException ioe) { - throw new MessagingException("Invalid attachment.", ioe); - } - } - - public void writeTo(OutputStream out) throws IOException, MessagingException { - InputStream in = getInputStream(); - Base64OutputStream base64Out = new Base64OutputStream(out); - IOUtils.copy(in, base64Out); - base64Out.close(); - } - - public Uri getContentUri() { - return mUri; - } - } -} diff --git a/src/com/fsck/k9/mail/store/Pop3Store.java b/src/com/fsck/k9/mail/store/Pop3Store.java deleted file mode 100644 index c3782efed..000000000 --- a/src/com/fsck/k9/mail/store/Pop3Store.java +++ /dev/null @@ -1,880 +0,0 @@ - -package com.fsck.k9.mail.store; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.SSLException; - -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.Utility; -import com.fsck.k9.mail.AuthenticationFailedException; -import com.fsck.k9.mail.FetchProfile; -import com.fsck.k9.mail.Flag; -import com.fsck.k9.mail.Folder; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessageRetrievalListener; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.CertificateValidationException; -import com.fsck.k9.mail.Folder.OpenMode; -import com.fsck.k9.mail.internet.MimeMessage; - -public class Pop3Store extends Store { - public static final int CONNECTION_SECURITY_NONE = 0; - public static final int CONNECTION_SECURITY_TLS_OPTIONAL = 1; - public static final int CONNECTION_SECURITY_TLS_REQUIRED = 2; - public static final int CONNECTION_SECURITY_SSL_REQUIRED = 3; - public static final int CONNECTION_SECURITY_SSL_OPTIONAL = 4; - - private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED }; - - private String mHost; - private int mPort; - private String mUsername; - private String mPassword; - private int mConnectionSecurity; - private HashMap mFolders = new HashMap(); - private Pop3Capabilities mCapabilities; - -// /** -// * Detected latency, used for usage scaling. -// * Usage scaling occurs when it is neccesary to get information about -// * messages that could result in large data loads. This value allows -// * the code that loads this data to decide between using large downloads -// * (high latency) or multiple round trips (low latency) to accomplish -// * the same thing. -// * Default is Integer.MAX_VALUE implying massive latency so that the large -// * download method is used by default until latency data is collected. -// */ -// private int mLatencyMs = Integer.MAX_VALUE; -// -// /** -// * Detected throughput, used for usage scaling. -// * Usage scaling occurs when it is neccesary to get information about -// * messages that could result in large data loads. This value allows -// * the code that loads this data to decide between using large downloads -// * (high latency) or multiple round trips (low latency) to accomplish -// * the same thing. -// * Default is Integer.MAX_VALUE implying massive bandwidth so that the -// * large download method is used by default until latency data is -// * collected. -// */ -// private int mThroughputKbS = Integer.MAX_VALUE; - - /** - * pop3://user:password@server:port CONNECTION_SECURITY_NONE - * pop3+tls://user:password@server:port CONNECTION_SECURITY_TLS_OPTIONAL - * pop3+tls+://user:password@server:port CONNECTION_SECURITY_TLS_REQUIRED - * pop3+ssl+://user:password@server:port CONNECTION_SECURITY_SSL_REQUIRED - * pop3+ssl://user:password@server:port CONNECTION_SECURITY_SSL_OPTIONAL - * - * @param _uri - */ - public Pop3Store(String _uri) throws MessagingException { - URI uri; - try { - uri = new URI(_uri); - } catch (URISyntaxException use) { - throw new MessagingException("Invalid Pop3Store URI", use); - } - - String scheme = uri.getScheme(); - if (scheme.equals("pop3")) { - mConnectionSecurity = CONNECTION_SECURITY_NONE; - mPort = 110; - } else if (scheme.equals("pop3+tls")) { - mConnectionSecurity = CONNECTION_SECURITY_TLS_OPTIONAL; - mPort = 110; - } else if (scheme.equals("pop3+tls+")) { - mConnectionSecurity = CONNECTION_SECURITY_TLS_REQUIRED; - mPort = 110; - } else if (scheme.equals("pop3+ssl+")) { - mConnectionSecurity = CONNECTION_SECURITY_SSL_REQUIRED; - mPort = 995; - } else if (scheme.equals("pop3+ssl")) { - mConnectionSecurity = CONNECTION_SECURITY_SSL_OPTIONAL; - mPort = 995; - } else { - throw new MessagingException("Unsupported protocol"); - } - - mHost = uri.getHost(); - - if (uri.getPort() != -1) { - mPort = uri.getPort(); - } - - if (uri.getUserInfo() != null) { - String[] userInfoParts = uri.getUserInfo().split(":", 2); - mUsername = userInfoParts[0]; - if (userInfoParts.length > 1) { - mPassword = userInfoParts[1]; - } - } - } - - @Override - public Folder getFolder(String name) throws MessagingException { - Folder folder = mFolders.get(name); - if (folder == null) { - folder = new Pop3Folder(name); - mFolders.put(folder.getName(), folder); - } - return folder; - } - - @Override - public Folder[] getPersonalNamespaces() throws MessagingException { - return new Folder[] { - getFolder("INBOX"), - }; - } - - @Override - public void checkSettings() throws MessagingException { - Pop3Folder folder = new Pop3Folder("INBOX"); - folder.open(OpenMode.READ_WRITE); - if (!mCapabilities.uidl) { - /* - * Run an additional test to see if UIDL is supported on the server. If it's not we - * can't service this account. - */ - try{ - /* - * If the server doesn't support UIDL it will return a - response, which causes - * executeSimpleCommand to throw a MessagingException, exiting this method. - */ - folder.executeSimpleCommand("UIDL"); - } - catch (IOException ioe) { - throw new MessagingException(null, ioe); - } - } - folder.close(false); - } - - class Pop3Folder extends Folder { - private Socket mSocket; - private InputStream mIn; - private OutputStream mOut; - private HashMap mUidToMsgMap = new HashMap(); - private HashMap mMsgNumToMsgMap = new HashMap(); - private HashMap mUidToMsgNumMap = new HashMap(); - private String mName; - private int mMessageCount; - - public Pop3Folder(String name) { - this.mName = name; - if (mName.equalsIgnoreCase("INBOX")) { - mName = "INBOX"; - } - } - - @Override - public synchronized void open(OpenMode mode) throws MessagingException { - if (isOpen()) { - return; - } - - if (!mName.equalsIgnoreCase("INBOX")) { - throw new MessagingException("Folder does not exist"); - } - - try { - SocketAddress socketAddress = new InetSocketAddress(mHost, mPort); - if (mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED || - mConnectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL) { - SSLContext sslContext = SSLContext.getInstance("TLS"); - final boolean secure = mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED; - sslContext.init(null, new TrustManager[] { - TrustManagerFactory.get(mHost, secure) - }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(); - mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - } else { - mSocket = new Socket(); - mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - } - - mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT); - - - // Eat the banner - executeSimpleCommand(null); - - mCapabilities = getCapabilities(); - - if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL - || mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { - if (mCapabilities.stls) { - writeLine("STLS"); - - SSLContext sslContext = SSLContext.getInstance("TLS"); - boolean secure = mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED; - sslContext.init(null, new TrustManager[] { - TrustManagerFactory.get(mHost, secure) - }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(mSocket, mHost, mPort, - true); - mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT); - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - } else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { - throw new MessagingException("TLS not supported but required"); - } - } - - try { - executeSimpleCommand("USER " + mUsername); - executeSimpleCommand("PASS " + mPassword); - } catch (MessagingException me) { - throw new AuthenticationFailedException(null, me); - } - } catch (SSLException e) { - throw new CertificateValidationException(e.getMessage(), e); - } catch (GeneralSecurityException gse) { - throw new MessagingException( - "Unable to open connection to POP server due to security error.", gse); - } catch (IOException ioe) { - throw new MessagingException("Unable to open connection to POP server.", ioe); - } - - try { - String response = executeSimpleCommand("STAT"); - String[] parts = response.split(" "); - mMessageCount = Integer.parseInt(parts[1]); - } - catch (IOException ioe) { - throw new MessagingException("Unable to STAT folder.", ioe); - } - mUidToMsgMap.clear(); - mMsgNumToMsgMap.clear(); - mUidToMsgNumMap.clear(); - } - - public boolean isOpen() { - return (mIn != null && mOut != null && mSocket != null && mSocket.isConnected() && !mSocket - .isClosed()); - } - - @Override - public OpenMode getMode() throws MessagingException { - return OpenMode.READ_ONLY; - } - - @Override - public void close(boolean expunge) { - try { - executeSimpleCommand("QUIT"); - } - catch (Exception e) { - /* - * QUIT may fail if the connection is already closed. We don't care. It's just - * being friendly. - */ - } - try { - mIn.close(); - } catch (Exception e) { - /* - * May fail if the connection is already closed. - */ - } - try { - mOut.close(); - } catch (Exception e) { - /* - * May fail if the connection is already closed. - */ - } - try { - mSocket.close(); - } catch (Exception e) { - /* - * May fail if the connection is already closed. - */ - } - mIn = null; - mOut = null; - mSocket = null; - } - - @Override - public String getName() { - return mName; - } - - @Override - public boolean create(FolderType type) throws MessagingException { - return false; - } - - @Override - public boolean exists() throws MessagingException { - return mName.equalsIgnoreCase("INBOX"); - } - - @Override - public int getMessageCount() { - return mMessageCount; - } - - @Override - public int getUnreadMessageCount() throws MessagingException { - return -1; - } - - @Override - public Message getMessage(String uid) throws MessagingException { - Pop3Message message = mUidToMsgMap.get(uid); - if (message == null) { - message = new Pop3Message(uid, this); - } - return message; - } - - @Override - public Message[] getMessages(int start, int end, MessageRetrievalListener listener) - throws MessagingException { - if (start < 1 || end < 1 || end < start) { - throw new MessagingException(String.format("Invalid message set %d %d", - start, end)); - } - try { - indexMsgNums(start, end); - } catch (IOException ioe) { - throw new MessagingException("getMessages", ioe); - } - ArrayList messages = new ArrayList(); - int i = 0; - for (int msgNum = start; msgNum <= end; msgNum++) { - Pop3Message message = mMsgNumToMsgMap.get(msgNum); - if (listener != null) { - listener.messageStarted(message.getUid(), i++, (end - start) + 1); - } - messages.add(message); - if (listener != null) { - listener.messageFinished(message, i++, (end - start) + 1); - } - } - return messages.toArray(new Message[messages.size()]); - } - - /** - * Ensures that the given message set (from start to end inclusive) - * has been queried so that uids are available in the local cache. - * @param start - * @param end - * @throws MessagingException - * @throws IOException - */ - private void indexMsgNums(int start, int end) - throws MessagingException, IOException { - int unindexedMessageCount = 0; - for (int msgNum = start; msgNum <= end; msgNum++) { - if (mMsgNumToMsgMap.get(msgNum) == null) { - unindexedMessageCount++; - } - } - if (unindexedMessageCount == 0) { - return; - } - if (unindexedMessageCount < 50 && mMessageCount > 5000) { - /* - * In extreme cases we'll do a UIDL command per message instead of a bulk - * download. - */ - for (int msgNum = start; msgNum <= end; msgNum++) { - Pop3Message message = mMsgNumToMsgMap.get(msgNum); - if (message == null) { - String response = executeSimpleCommand("UIDL " + msgNum); - int uidIndex = response.lastIndexOf(' '); - String msgUid = response.substring(uidIndex + 1); - message = new Pop3Message(msgUid, this); - indexMessage(msgNum, message); - } - } - } - else { - String response = executeSimpleCommand("UIDL"); - while ((response = readLine()) != null) { - if (response.equals(".")) { - break; - } - String[] uidParts = response.split(" "); - Integer msgNum = Integer.valueOf(uidParts[0]); - String msgUid = uidParts[1]; - if (msgNum >= start && msgNum <= end) { - Pop3Message message = mMsgNumToMsgMap.get(msgNum); - if (message == null) { - message = new Pop3Message(msgUid, this); - indexMessage(msgNum, message); - } - } - } - } - } - - private void indexUids(ArrayList uids) - throws MessagingException, IOException { - HashSet unindexedUids = new HashSet(); - for (String uid : uids) { - if (mUidToMsgMap.get(uid) == null) { - unindexedUids.add(uid); - } - } - if (unindexedUids.size() == 0) { - return; - } - /* - * If we are missing uids in the cache the only sure way to - * get them is to do a full UIDL list. A possible optimization - * would be trying UIDL for the latest X messages and praying. - */ - String response = executeSimpleCommand("UIDL"); - while ((response = readLine()) != null) { - if (response.equals(".")) { - break; - } - String[] uidParts = response.split(" "); - Integer msgNum = Integer.valueOf(uidParts[0]); - String msgUid = uidParts[1]; - if (unindexedUids.contains(msgUid)) { - if (Config.LOGD) { - Pop3Message message = mUidToMsgMap.get(msgUid); - if (message == null) { - message = new Pop3Message(msgUid, this); - } - indexMessage(msgNum, message); - } - } - } - } - - private void indexMessage(int msgNum, Pop3Message message) { - mMsgNumToMsgMap.put(msgNum, message); - mUidToMsgMap.put(message.getUid(), message); - mUidToMsgNumMap.put(message.getUid(), msgNum); - } - - @Override - public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException { - throw new UnsupportedOperationException("Pop3Folder.getMessage(MessageRetrievalListener)"); - } - - @Override - public Message[] getMessages(String[] uids, MessageRetrievalListener listener) - throws MessagingException { - throw new UnsupportedOperationException("Pop3Folder.getMessage(MessageRetrievalListener)"); - } - - /** - * Fetch the items contained in the FetchProfile into the given set of - * Messages in as efficient a manner as possible. - * @param messages - * @param fp - * @throws MessagingException - */ - public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener) - throws MessagingException { - if (messages == null || messages.length == 0) { - return; - } - ArrayList uids = new ArrayList(); - for (Message message : messages) { - uids.add(message.getUid()); - } - try { - indexUids(uids); - } - catch (IOException ioe) { - throw new MessagingException("fetch", ioe); - } - try { - if (fp.contains(FetchProfile.Item.ENVELOPE)) { - /* - * We pass the listener only if there are other things to do in the - * FetchProfile. Since fetchEnvelop works in bulk and eveything else - * works one at a time if we let fetchEnvelope send events the - * event would get sent twice. - */ - fetchEnvelope(messages, fp.size() == 1 ? listener : null); - } - } - catch (IOException ioe) { - throw new MessagingException("fetch", ioe); - } - for (int i = 0, count = messages.length; i < count; i++) { - Message message = messages[i]; - if (!(message instanceof Pop3Message)) { - throw new MessagingException("Pop3Store.fetch called with non-Pop3 Message"); - } - Pop3Message pop3Message = (Pop3Message)message; - try { - if (listener != null && !fp.contains(FetchProfile.Item.ENVELOPE)) { - listener.messageStarted(pop3Message.getUid(), i, count); - } - if (fp.contains(FetchProfile.Item.BODY)) { - fetchBody(pop3Message, -1); - } - else if (fp.contains(FetchProfile.Item.BODY_SANE)) { - /* - * To convert the suggested download size we take the size - * divided by the maximum line size (76). - */ - fetchBody(pop3Message, - FETCH_BODY_SANE_SUGGESTED_SIZE / 76); - } - else if (fp.contains(FetchProfile.Item.STRUCTURE)) { - /* - * If the user is requesting STRUCTURE we are required to set the body - * to null since we do not support the function. - */ - pop3Message.setBody(null); - } - if (listener != null && !fp.contains(FetchProfile.Item.ENVELOPE)) { - listener.messageFinished(message, i, count); - } - } catch (IOException ioe) { - throw new MessagingException("Unable to fetch message", ioe); - } - } - } - - private void fetchEnvelope(Message[] messages, - MessageRetrievalListener listener) throws IOException, MessagingException { - int unsizedMessages = 0; - for (Message message : messages) { - if (message.getSize() == -1) { - unsizedMessages++; - } - } - if (unsizedMessages == 0) { - return; - } - if (unsizedMessages < 50 && mMessageCount > 5000) { - /* - * In extreme cases we'll do a command per message instead of a bulk request - * to hopefully save some time and bandwidth. - */ - for (int i = 0, count = messages.length; i < count; i++) { - Message message = messages[i]; - if (!(message instanceof Pop3Message)) { - throw new MessagingException("Pop3Store.fetch called with non-Pop3 Message"); - } - Pop3Message pop3Message = (Pop3Message)message; - if (listener != null) { - listener.messageStarted(pop3Message.getUid(), i, count); - } - String response = executeSimpleCommand(String.format("LIST %d", - mUidToMsgNumMap.get(pop3Message.getUid()))); - String[] listParts = response.split(" "); - int msgNum = Integer.parseInt(listParts[1]); - int msgSize = Integer.parseInt(listParts[2]); - pop3Message.setSize(msgSize); - if (listener != null) { - listener.messageFinished(pop3Message, i, count); - } - } - } - else { - HashSet msgUidIndex = new HashSet(); - for (Message message : messages) { - msgUidIndex.add(message.getUid()); - } - int i = 0, count = messages.length; - String response = executeSimpleCommand("LIST"); - while ((response = readLine()) != null) { - if (response.equals(".")) { - break; - } - String[] listParts = response.split(" "); - int msgNum = Integer.parseInt(listParts[0]); - int msgSize = Integer.parseInt(listParts[1]); - Pop3Message pop3Message = mMsgNumToMsgMap.get(msgNum); - if (pop3Message != null && msgUidIndex.contains(pop3Message.getUid())) { - if (listener != null) { - listener.messageStarted(pop3Message.getUid(), i, count); - } - pop3Message.setSize(msgSize); - if (listener != null) { - listener.messageFinished(pop3Message, i, count); - } - i++; - } - } - } - } - - /** - * Fetches the body of the given message, limiting the stored data - * to the specified number of lines. If lines is -1 the entire message - * is fetched. This is implemented with RETR for lines = -1 or TOP - * for any other value. If the server does not support TOP it is - * emulated with RETR and extra lines are thrown away. - * @param message - * @param lines - */ - private void fetchBody(Pop3Message message, int lines) - throws IOException, MessagingException { - String response = null; - if (lines == -1 || !mCapabilities.top) { - response = executeSimpleCommand(String.format("RETR %d", - mUidToMsgNumMap.get(message.getUid()))); - } - else { - response = executeSimpleCommand(String.format("TOP %d %d", - mUidToMsgNumMap.get(message.getUid()), - lines)); - } - if (response != null) { - try { - message.parse(new Pop3ResponseInputStream(mIn)); - } - catch (MessagingException me) { - /* - * If we're only downloading headers it's possible - * we'll get a broken MIME message which we're not - * real worried about. If we've downloaded the body - * and can't parse it we need to let the user know. - */ - if (lines == -1) { - throw me; - } - } - } - } - - @Override - public Flag[] getPermanentFlags() throws MessagingException { - return PERMANENT_FLAGS; - } - - public void appendMessages(Message[] messages) throws MessagingException { - } - - public void delete(boolean recurse) throws MessagingException { - } - - public Message[] expunge() throws MessagingException { - return null; - } - - public void setFlags(Message[] messages, Flag[] flags, boolean value) - throws MessagingException { - if (!value || !Utility.arrayContains(flags, Flag.DELETED)) { - /* - * The only flagging we support is setting the Deleted flag. - */ - return; - } - try { - for (Message message : messages) { - executeSimpleCommand(String.format("DELE %s", - mUidToMsgNumMap.get(message.getUid()))); - } - } - catch (IOException ioe) { - throw new MessagingException("setFlags()", ioe); - } - } - - @Override - public void copyMessages(Message[] msgs, Folder folder) throws MessagingException { - throw new UnsupportedOperationException("copyMessages is not supported in POP3"); - } - -// private boolean isRoundTripModeSuggested() { -// long roundTripMethodMs = -// (uncachedMessageCount * 2 * mLatencyMs); -// long bulkMethodMs = -// (mMessageCount * 58) / (mThroughputKbS * 1024 / 8) * 1000; -// } - - private String readLine() throws IOException { - StringBuffer sb = new StringBuffer(); - int d = mIn.read(); - if (d == -1) { - throw new IOException("End of stream reached while trying to read line."); - } - do { - if (((char)d) == '\r') { - continue; - } else if (((char)d) == '\n') { - break; - } else { - sb.append((char)d); - } - } while ((d = mIn.read()) != -1); - String ret = sb.toString(); - if (Config.LOGD) { - if (k9.DEBUG) { - Log.d(k9.LOG_TAG, "<<< " + ret); - } - } - return ret; - } - - private void writeLine(String s) throws IOException { - if (Config.LOGD) { - if (k9.DEBUG) { - Log.d(k9.LOG_TAG, ">>> " + s); - } - } - mOut.write(s.getBytes()); - mOut.write('\r'); - mOut.write('\n'); - mOut.flush(); - } - - private Pop3Capabilities getCapabilities() throws IOException, MessagingException { - Pop3Capabilities capabilities = new Pop3Capabilities(); - try { - String response = executeSimpleCommand("CAPA"); - while ((response = readLine()) != null) { - if (response.equals(".")) { - break; - } - if (response.equalsIgnoreCase("STLS")){ - capabilities.stls = true; - } - else if (response.equalsIgnoreCase("UIDL")) { - capabilities.uidl = true; - } - else if (response.equalsIgnoreCase("PIPELINING")) { - capabilities.pipelining = true; - } - else if (response.equalsIgnoreCase("USER")) { - capabilities.user = true; - } - else if (response.equalsIgnoreCase("TOP")) { - capabilities.top = true; - } - } - } - catch (MessagingException me) { - /* - * The server may not support the CAPA command, so we just eat this Exception - * and allow the empty capabilities object to be returned. - */ - } - return capabilities; - } - - private String executeSimpleCommand(String command) throws IOException, MessagingException { - open(OpenMode.READ_WRITE); - - if (command != null) { - writeLine(command); - } - - String response = readLine(); - - if (response.length() > 1 && response.charAt(0) == '-') { - throw new MessagingException(response); - } - - return response; - } - - @Override - public boolean equals(Object o) { - if (o instanceof Pop3Folder) { - return ((Pop3Folder) o).mName.equals(mName); - } - return super.equals(o); - } - } - - class Pop3Message extends MimeMessage { - public Pop3Message(String uid, Pop3Folder folder) throws MessagingException { - mUid = uid; - mFolder = folder; - mSize = -1; - } - - public void setSize(int size) { - mSize = size; - } - - protected void parse(InputStream in) throws IOException, MessagingException { - super.parse(in); - } - - @Override - public void setFlag(Flag flag, boolean set) throws MessagingException { - super.setFlag(flag, set); - mFolder.setFlags(new Message[] { this }, new Flag[] { flag }, set); - } - } - - class Pop3Capabilities { - public boolean stls; - public boolean top; - public boolean user; - public boolean uidl; - public boolean pipelining; - - public String toString() { - return String.format("STLS %b, TOP %b, USER %b, UIDL %b, PIPELINING %b", - stls, - top, - user, - uidl, - pipelining); - } - } - - class Pop3ResponseInputStream extends InputStream { - InputStream mIn; - boolean mStartOfLine = true; - boolean mFinished; - - public Pop3ResponseInputStream(InputStream in) { - mIn = in; - } - - @Override - public int read() throws IOException { - if (mFinished) { - return -1; - } - int d = mIn.read(); - if (mStartOfLine && d == '.') { - d = mIn.read(); - if (d == '\r') { - mFinished = true; - mIn.read(); - return -1; - } - } - - mStartOfLine = (d == '\n'); - - return d; - } - } -} diff --git a/src/com/fsck/k9/mail/store/TrustManagerFactory.java b/src/com/fsck/k9/mail/store/TrustManagerFactory.java deleted file mode 100644 index dcfa2070c..000000000 --- a/src/com/fsck/k9/mail/store/TrustManagerFactory.java +++ /dev/null @@ -1,95 +0,0 @@ - -package com.fsck.k9.mail.store; - -import android.util.Log; -import android.net.http.DomainNameChecker; - -import java.security.KeyStore; -import java.security.NoSuchAlgorithmException; -import java.security.KeyStoreException; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateException; - -import javax.net.ssl.X509TrustManager; -import javax.net.ssl.TrustManager; - -public final class TrustManagerFactory { - private static final String LOG_TAG = "TrustManagerFactory"; - - private static X509TrustManager sSecureTrustManager; - private static X509TrustManager sUnsecureTrustManager; - - private static class SimpleX509TrustManager implements X509TrustManager { - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } - - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } - - private static class SecureX509TrustManager implements X509TrustManager { - private X509TrustManager mTrustManager; - private String mHost; - - SecureX509TrustManager(X509TrustManager trustManager, String host) { - mTrustManager = trustManager; - mHost = host; - } - - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - mTrustManager.checkClientTrusted(chain, authType); - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - - mTrustManager.checkServerTrusted(chain, authType); - - if (!DomainNameChecker.match(chain[0], mHost)) { - throw new CertificateException("Certificate domain name does not match " - + mHost); - } - } - - public X509Certificate[] getAcceptedIssuers() { - return mTrustManager.getAcceptedIssuers(); - } - } - - static { - try { - javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509"); - tmf.init((KeyStore) null); - TrustManager[] tms = tmf.getTrustManagers(); - if (tms != null) { - for (TrustManager tm : tms) { - if (tm instanceof X509TrustManager) { - sSecureTrustManager = (X509TrustManager) tm; - break; - } - } - } - } catch (NoSuchAlgorithmException e) { - Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e); - } catch (KeyStoreException e) { - Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e); - } - - sUnsecureTrustManager = new SimpleX509TrustManager(); - } - - private TrustManagerFactory() { - } - - public static X509TrustManager get(String host, boolean secure) { - return secure ? new SecureX509TrustManager(sSecureTrustManager, host) : - sUnsecureTrustManager; - } -} diff --git a/src/com/fsck/k9/mail/transport/CountingOutputStream.java b/src/com/fsck/k9/mail/transport/CountingOutputStream.java deleted file mode 100644 index 51a786c8c..000000000 --- a/src/com/fsck/k9/mail/transport/CountingOutputStream.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.fsck.k9.mail.transport; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * A simple OutputStream that does nothing but count how many bytes are written to it and - * makes that count available to callers. - */ -public class CountingOutputStream extends OutputStream { - private long mCount; - - public CountingOutputStream() { - } - - public long getCount() { - return mCount; - } - - @Override - public void write(int oneByte) throws IOException { - mCount++; - } -} diff --git a/src/com/fsck/k9/mail/transport/EOLConvertingOutputStream.java b/src/com/fsck/k9/mail/transport/EOLConvertingOutputStream.java deleted file mode 100644 index 02d465615..000000000 --- a/src/com/fsck/k9/mail/transport/EOLConvertingOutputStream.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.fsck.k9.mail.transport; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -public class EOLConvertingOutputStream extends FilterOutputStream { - int lastChar; - - public EOLConvertingOutputStream(OutputStream out) { - super(out); - } - - @Override - public void write(int oneByte) throws IOException { - if (oneByte == '\n') { - if (lastChar != '\r') { - super.write('\r'); - } - } - super.write(oneByte); - lastChar = oneByte; - } - - @Override - public void flush() throws IOException { - if (lastChar == '\r') { - super.write('\n'); - lastChar = '\n'; - } - super.flush(); - } -} diff --git a/src/com/fsck/k9/mail/transport/SmtpTransport.java b/src/com/fsck/k9/mail/transport/SmtpTransport.java deleted file mode 100644 index d02b27364..000000000 --- a/src/com/fsck/k9/mail/transport/SmtpTransport.java +++ /dev/null @@ -1,376 +0,0 @@ - -package com.fsck.k9.mail.transport; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; -import java.security.SecureRandom; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.SSLException; - -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.k9; -import com.fsck.k9.PeekableInputStream; -import com.fsck.k9.codec.binary.Base64; -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.AuthenticationFailedException; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Transport; -import com.fsck.k9.mail.CertificateValidationException; -import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.store.TrustManagerFactory; - -public class SmtpTransport extends Transport { - public static final int CONNECTION_SECURITY_NONE = 0; - - public static final int CONNECTION_SECURITY_TLS_OPTIONAL = 1; - - public static final int CONNECTION_SECURITY_TLS_REQUIRED = 2; - - public static final int CONNECTION_SECURITY_SSL_REQUIRED = 3; - - public static final int CONNECTION_SECURITY_SSL_OPTIONAL = 4; - - String mHost; - - int mPort; - - String mUsername; - - String mPassword; - - int mConnectionSecurity; - - boolean mSecure; - - Socket mSocket; - - PeekableInputStream mIn; - - OutputStream mOut; - - /** - * smtp://user:password@server:port CONNECTION_SECURITY_NONE - * smtp+tls://user:password@server:port CONNECTION_SECURITY_TLS_OPTIONAL - * smtp+tls+://user:password@server:port CONNECTION_SECURITY_TLS_REQUIRED - * smtp+ssl+://user:password@server:port CONNECTION_SECURITY_SSL_REQUIRED - * smtp+ssl://user:password@server:port CONNECTION_SECURITY_SSL_OPTIONAL - * - * @param _uri - */ - public SmtpTransport(String _uri) throws MessagingException { - URI uri; - try { - uri = new URI(_uri); - } catch (URISyntaxException use) { - throw new MessagingException("Invalid SmtpTransport URI", use); - } - - String scheme = uri.getScheme(); - if (scheme.equals("smtp")) { - mConnectionSecurity = CONNECTION_SECURITY_NONE; - mPort = 25; - } else if (scheme.equals("smtp+tls")) { - mConnectionSecurity = CONNECTION_SECURITY_TLS_OPTIONAL; - mPort = 25; - } else if (scheme.equals("smtp+tls+")) { - mConnectionSecurity = CONNECTION_SECURITY_TLS_REQUIRED; - mPort = 25; - } else if (scheme.equals("smtp+ssl+")) { - mConnectionSecurity = CONNECTION_SECURITY_SSL_REQUIRED; - mPort = 465; - } else if (scheme.equals("smtp+ssl")) { - mConnectionSecurity = CONNECTION_SECURITY_SSL_OPTIONAL; - mPort = 465; - } else { - throw new MessagingException("Unsupported protocol"); - } - - mHost = uri.getHost(); - - if (uri.getPort() != -1) { - mPort = uri.getPort(); - } - - if (uri.getUserInfo() != null) { - String[] userInfoParts = uri.getUserInfo().split(":", 2); - mUsername = userInfoParts[0]; - if (userInfoParts.length > 1) { - mPassword = userInfoParts[1]; - } - } - } - - public void open() throws MessagingException { - try { - SocketAddress socketAddress = new InetSocketAddress(mHost, mPort); - if (mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED || - mConnectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL) { - SSLContext sslContext = SSLContext.getInstance("TLS"); - boolean secure = mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED; - sslContext.init(null, new TrustManager[] { - TrustManagerFactory.get(mHost, secure) - }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(); - mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); - mSecure = true; - } else { - mSocket = new Socket(); - mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); - } - - mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(), 1024)); - mOut = mSocket.getOutputStream(); - - // Eat the banner - executeSimpleCommand(null); - - String localHost = "localhost.localdomain"; - try { - InetAddress localAddress = InetAddress.getLocalHost(); - if (! localAddress.isLoopbackAddress()) { - // The loopback address will resolve to 'localhost' - // some mail servers only accept qualified hostnames, so make sure - // never to override "localhost.localdomain" with "localhost" - // TODO - this is a hack. but a better hack than what was there before - localHost = localAddress.getHostName(); - } - } catch (Exception e) { - if (Config.LOGD) { - if (k9.DEBUG) { - Log.d(k9.LOG_TAG, "Unable to look up localhost"); - } - } - } - - String result = executeSimpleCommand("EHLO " + localHost); - - /* - * TODO may need to add code to fall back to HELO I switched it from - * using HELO on non STARTTLS connections because of AOL's mail - * server. It won't let you use AUTH without EHLO. - * We should really be paying more attention to the capabilities - * and only attempting auth if it's available, and warning the user - * if not. - */ - if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL - || mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { - if (result.contains("-STARTTLS")) { - executeSimpleCommand("STARTTLS"); - - SSLContext sslContext = SSLContext.getInstance("TLS"); - boolean secure = mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED; - sslContext.init(null, new TrustManager[] { - TrustManagerFactory.get(mHost, secure) - }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(mSocket, mHost, mPort, - true); - mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(), - 1024)); - mOut = mSocket.getOutputStream(); - mSecure = true; - /* - * Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically, - * Exim. - */ - result = executeSimpleCommand("EHLO " + localHost); - } else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { - throw new MessagingException("TLS not supported but required"); - } - } - - /* - * result contains the results of the EHLO in concatenated form - */ - boolean authLoginSupported = result.matches(".*AUTH.*LOGIN.*$"); - boolean authPlainSupported = result.matches(".*AUTH.*PLAIN.*$"); - - if (mUsername != null && mUsername.length() > 0 && mPassword != null - && mPassword.length() > 0) { - if (authPlainSupported) { - saslAuthPlain(mUsername, mPassword); - } - else if (authLoginSupported) { - saslAuthLogin(mUsername, mPassword); - } - else { - throw new MessagingException("No valid authentication mechanism found."); - } - } - } catch (SSLException e) { - throw new CertificateValidationException(e.getMessage(), e); - } catch (GeneralSecurityException gse) { - throw new MessagingException( - "Unable to open connection to SMTP server due to security error.", gse); - } catch (IOException ioe) { - throw new MessagingException("Unable to open connection to SMTP server.", ioe); - } - } - - public void sendMessage(Message message) throws MessagingException { - close(); - open(); - Address[] from = message.getFrom(); - - try { - executeSimpleCommand("MAIL FROM: " + "<" + from[0].getAddress() + ">"); - for (Address address : message.getRecipients(RecipientType.TO)) { - executeSimpleCommand("RCPT TO: " + "<" + address.getAddress() + ">"); - } - for (Address address : message.getRecipients(RecipientType.CC)) { - executeSimpleCommand("RCPT TO: " + "<" + address.getAddress() + ">"); - } - for (Address address : message.getRecipients(RecipientType.BCC)) { - executeSimpleCommand("RCPT TO: " + "<" + address.getAddress() + ">"); - } - message.setRecipients(RecipientType.BCC, null); - executeSimpleCommand("DATA"); - // TODO byte stuffing - message.writeTo( - new EOLConvertingOutputStream( - new BufferedOutputStream(mOut, 1024))); - executeSimpleCommand("\r\n."); - } catch (IOException ioe) { - throw new MessagingException("Unable to send message", ioe); - } - } - - public void close() { - try { - mIn.close(); - } catch (Exception e) { - - } - try { - mOut.close(); - } catch (Exception e) { - - } - try { - mSocket.close(); - } catch (Exception e) { - - } - mIn = null; - mOut = null; - mSocket = null; - } - - private String readLine() throws IOException { - StringBuffer sb = new StringBuffer(); - int d; - while ((d = mIn.read()) != -1) { - if (((char)d) == '\r') { - continue; - } else if (((char)d) == '\n') { - break; - } else { - sb.append((char)d); - } - } - String ret = sb.toString(); - if (Config.LOGD) { - if (k9.DEBUG) { - Log.d(k9.LOG_TAG, "<<< " + ret); - } - } - return ret; - } - - private void writeLine(String s) throws IOException { - if (Config.LOGD) { - if (k9.DEBUG) { - Log.d(k9.LOG_TAG, ">>> " + s); - } - } - mOut.write(s.getBytes()); - mOut.write('\r'); - mOut.write('\n'); - mOut.flush(); - } - - private String executeSimpleCommand(String command) throws IOException, MessagingException { - if (command != null) { - writeLine(command); - } - - String line = readLine(); - - String result = line; - - while (line.length() >= 4 && line.charAt(3) == '-') { - line = readLine(); - result += line.substring(3); - } - - char c = result.charAt(0); - if ((c == '4') || (c == '5')) { - throw new MessagingException(result); - } - - return result; - } - - -// C: AUTH LOGIN -// S: 334 VXNlcm5hbWU6 -// C: d2VsZG9u -// S: 334 UGFzc3dvcmQ6 -// C: dzNsZDBu -// S: 235 2.0.0 OK Authenticated -// -// Lines 2-5 of the conversation contain base64-encoded information. The same conversation, with base64 strings decoded, reads: -// -// -// C: AUTH LOGIN -// S: 334 Username: -// C: weldon -// S: 334 Password: -// C: w3ld0n -// S: 235 2.0.0 OK Authenticated - - private void saslAuthLogin(String username, String password) throws MessagingException, - AuthenticationFailedException, IOException { - try { - executeSimpleCommand("AUTH LOGIN"); - executeSimpleCommand(new String(Base64.encodeBase64(username.getBytes()))); - executeSimpleCommand(new String(Base64.encodeBase64(password.getBytes()))); - } - catch (MessagingException me) { - if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') { - throw new AuthenticationFailedException("AUTH LOGIN failed (" + me.getMessage() - + ")"); - } - throw me; - } - } - - private void saslAuthPlain(String username, String password) throws MessagingException, - AuthenticationFailedException, IOException { - byte[] data = ("\000" + username + "\000" + password).getBytes(); - data = new Base64().encode(data); - try { - executeSimpleCommand("AUTH PLAIN " + new String(data)); - } - catch (MessagingException me) { - if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') { - throw new AuthenticationFailedException("AUTH PLAIN failed (" + me.getMessage() - + ")"); - } - throw me; - } - } -} diff --git a/src/com/fsck/k9/mail/transport/StatusOutputStream.java b/src/com/fsck/k9/mail/transport/StatusOutputStream.java deleted file mode 100644 index c97e08e2e..000000000 --- a/src/com/fsck/k9/mail/transport/StatusOutputStream.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.fsck.k9.mail.transport; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import com.fsck.k9.k9; - -import android.util.Config; -import android.util.Log; - -public class StatusOutputStream extends FilterOutputStream { - private long mCount = 0; - - public StatusOutputStream(OutputStream out) { - super(out); - } - - @Override - public void write(int oneByte) throws IOException { - super.write(oneByte); - mCount++; - if (Config.LOGV) { - if (mCount % 1024 == 0) { - Log.v(k9.LOG_TAG, "# " + mCount); - } - } - } -} diff --git a/src/com/fsck/k9/provider/AttachmentProvider.java b/src/com/fsck/k9/provider/AttachmentProvider.java deleted file mode 100644 index 70e0dbb2c..000000000 --- a/src/com/fsck/k9/provider/AttachmentProvider.java +++ /dev/null @@ -1,272 +0,0 @@ -package com.fsck.k9.provider; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.provider.OpenableColumns; -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.Utility; -import com.fsck.k9.mail.internet.MimeUtility; - -/* - * A simple ContentProvider that allows file access to Email's attachments. - */ -public class AttachmentProvider extends ContentProvider { - public static final Uri CONTENT_URI = Uri.parse( "content://com.fsck.k9.attachmentprovider"); - - private static final String FORMAT_RAW = "RAW"; - private static final String FORMAT_THUMBNAIL = "THUMBNAIL"; - - public static class AttachmentProviderColumns { - public static final String _ID = "_id"; - public static final String DATA = "_data"; - public static final String DISPLAY_NAME = "_display_name"; - public static final String SIZE = "_size"; - } - - public static Uri getAttachmentUri(Account account, long id) { - return CONTENT_URI.buildUpon() - .appendPath(account.getUuid() + ".db") - .appendPath(Long.toString(id)) - .appendPath(FORMAT_RAW) - .build(); - } - - public static Uri getAttachmentThumbnailUri(Account account, long id, int width, int height) { - return CONTENT_URI.buildUpon() - .appendPath(account.getUuid() + ".db") - .appendPath(Long.toString(id)) - .appendPath(FORMAT_THUMBNAIL) - .appendPath(Integer.toString(width)) - .appendPath(Integer.toString(height)) - .build(); - } - - public static Uri getAttachmentUri(String db, long id) { - return CONTENT_URI.buildUpon() - .appendPath(db) - .appendPath(Long.toString(id)) - .appendPath(FORMAT_RAW) - .build(); - } - - @Override - public boolean onCreate() { - /* - * We use the cache dir as a temporary directory (since Android doesn't give us one) so - * on startup we'll clean up any .tmp files from the last run. - */ - File[] files = getContext().getCacheDir().listFiles(); - for (File file : files) { - if (file.getName().endsWith(".tmp")) { - file.delete(); - } - } - return true; - } - - @Override - public String getType(Uri uri) { - List segments = uri.getPathSegments(); - String dbName = segments.get(0); - String id = segments.get(1); - String format = segments.get(2); - if (FORMAT_THUMBNAIL.equals(format)) { - return "image/png"; - } - else { - String path = getContext().getDatabasePath(dbName).getAbsolutePath(); - SQLiteDatabase db = null; - Cursor cursor = null; - try { - db = SQLiteDatabase.openDatabase(path, null, 0); - cursor = db.query( - "attachments", - new String[] { "mime_type" }, - "id = ?", - new String[] { id }, - null, - null, - null); - cursor.moveToFirst(); - String type = cursor.getString(0); - cursor.close(); - db.close(); - return type; - - } - finally { - if (cursor != null) { - cursor.close(); - } - if (db != null) { - db.close(); - } - - } - } - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - List segments = uri.getPathSegments(); - String dbName = segments.get(0); - String id = segments.get(1); - String format = segments.get(2); - if (FORMAT_THUMBNAIL.equals(format)) { - int width = Integer.parseInt(segments.get(3)); - int height = Integer.parseInt(segments.get(4)); - String filename = "thmb_" + dbName + "_" + id; - File dir = getContext().getCacheDir(); - File file = new File(dir, filename); - if (!file.exists()) { - Uri attachmentUri = getAttachmentUri(dbName, Long.parseLong(id)); - String type = getType(attachmentUri); - try { - FileInputStream in = new FileInputStream( - new File(getContext().getDatabasePath(dbName + "_att"), id)); - Bitmap thumbnail = createThumbnail(type, in); - thumbnail = thumbnail.createScaledBitmap(thumbnail, width, height, true); - FileOutputStream out = new FileOutputStream(file); - thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out); - out.close(); - in.close(); - } - catch (IOException ioe) { - return null; - } - } - return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); - } - else { - return ParcelFileDescriptor.open( - new File(getContext().getDatabasePath(dbName + "_att"), id), - ParcelFileDescriptor.MODE_READ_ONLY); - } - } - - @Override - public int delete(Uri uri, String arg1, String[] arg2) { - return 0; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - if (projection == null) { - projection = - new String[] { - AttachmentProviderColumns._ID, - AttachmentProviderColumns.DATA, - }; - } - - List segments = uri.getPathSegments(); - String dbName = segments.get(0); - String id = segments.get(1); - String format = segments.get(2); - String path = getContext().getDatabasePath(dbName).getAbsolutePath(); - String name = null; - int size = -1; - SQLiteDatabase db = null; - Cursor cursor = null; - try { - db = SQLiteDatabase.openDatabase(path, null, 0); - cursor = db.query( - "attachments", - new String[] { "name", "size" }, - "id = ?", - new String[] { id }, - null, - null, - null); - if (!cursor.moveToFirst()) { - return null; - } - name = cursor.getString(0); - size = cursor.getInt(1); - } - finally { - if (cursor != null) { - cursor.close(); - } - if (db != null) { - db.close(); - } - } - - MatrixCursor ret = new MatrixCursor(projection); - Object[] values = new Object[projection.length]; - for (int i = 0, count = projection.length; i < count; i++) { - String column = projection[i]; - if (AttachmentProviderColumns._ID.equals(column)) { - values[i] = id; - } - else if (AttachmentProviderColumns.DATA.equals(column)) { - values[i] = uri.toString(); - } - else if (AttachmentProviderColumns.DISPLAY_NAME.equals(column)) { - values[i] = name; - } - else if (AttachmentProviderColumns.SIZE.equals(column)) { - values[i] = size; - } - } - ret.addRow(values); - return ret; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } - - private Bitmap createThumbnail(String type, InputStream data) { - if(MimeUtility.mimeTypeMatches(type, "image/*")) { - return createImageThumbnail(data); - } - return null; - } - - private Bitmap createImageThumbnail(InputStream data) { - try { - Bitmap bitmap = BitmapFactory.decodeStream(data); - return bitmap; - } - catch (OutOfMemoryError oome) { - /* - * Improperly downloaded images, corrupt bitmaps and the like can commonly - * cause OOME due to invalid allocation sizes. We're happy with a null bitmap in - * that case. If the system is really out of memory we'll know about it soon - * enough. - */ - return null; - } - catch (Exception e) { - return null; - } - } -} diff --git a/src/com/fsck/k9/service/BootReceiver.java b/src/com/fsck/k9/service/BootReceiver.java deleted file mode 100644 index 19714e34e..000000000 --- a/src/com/fsck/k9/service/BootReceiver.java +++ /dev/null @@ -1,22 +0,0 @@ - -package com.fsck.k9.service; - -import com.fsck.k9.MessagingController; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -public class BootReceiver extends BroadcastReceiver { - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { - MailService.actionReschedule(context); - } - else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(intent.getAction())) { - MailService.actionCancel(context); - } - else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(intent.getAction())) { - MailService.actionReschedule(context); - } - } -} diff --git a/src/com/fsck/k9/service/MailService.java b/src/com/fsck/k9/service/MailService.java deleted file mode 100644 index b0a76db84..000000000 --- a/src/com/fsck/k9/service/MailService.java +++ /dev/null @@ -1,193 +0,0 @@ - -package com.fsck.k9.service; - -import java.util.HashMap; - -import android.app.AlarmManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.os.SystemClock; -import android.util.Config; -import android.util.Log; -import android.text.TextUtils; -import android.net.Uri; - -import com.fsck.k9.Account; -import com.fsck.k9.k9; -import com.fsck.k9.MessagingController; -import com.fsck.k9.MessagingListener; -import com.fsck.k9.Preferences; -import com.fsck.k9.R; -import com.fsck.k9.activity.Accounts; -import com.fsck.k9.activity.FolderMessageList; - -/** - */ -public class MailService extends Service { - private static final String ACTION_CHECK_MAIL = "com.fsck.k9.intent.action.MAIL_SERVICE_WAKEUP"; - private static final String ACTION_RESCHEDULE = "com.fsck.k9.intent.action.MAIL_SERVICE_RESCHEDULE"; - private static final String ACTION_CANCEL = "com.fsck.k9.intent.action.MAIL_SERVICE_CANCEL"; - - private Listener mListener = new Listener(); - - private int mStartId; - - public static void actionReschedule(Context context) { - Intent i = new Intent(); - i.setClass(context, MailService.class); - i.setAction(MailService.ACTION_RESCHEDULE); - context.startService(i); - } - - public static void actionCancel(Context context) { - Intent i = new Intent(); - i.setClass(context, MailService.class); - i.setAction(MailService.ACTION_CANCEL); - context.startService(i); - } - - @Override - public void onStart(Intent intent, int startId) { - super.onStart(intent, startId); - this.mStartId = startId; - - MessagingController.getInstance(getApplication()).addListener(mListener); - if (ACTION_CHECK_MAIL.equals(intent.getAction())) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "***** MailService *****: checking mail"); - } - MessagingController.getInstance(getApplication()).checkMail(this, null, mListener); - } - else if (ACTION_CANCEL.equals(intent.getAction())) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "***** MailService *****: cancel"); - } - cancel(); - stopSelf(startId); - } - else if (ACTION_RESCHEDULE.equals(intent.getAction())) { - if (Config.LOGV) { - Log.v(k9.LOG_TAG, "***** MailService *****: reschedule"); - } - reschedule(); - stopSelf(startId); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - MessagingController.getInstance(getApplication()).removeListener(mListener); - } - - private void cancel() { - AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); - Intent i = new Intent(); - i.setClassName("com.fsck.k9", "com.fsck.k9.service.MailService"); - i.setAction(ACTION_CHECK_MAIL); - PendingIntent pi = PendingIntent.getService(this, 0, i, 0); - alarmMgr.cancel(pi); - } - - private void reschedule() { - AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); - Intent i = new Intent(); - i.setClassName("com.fsck.k9", "com.fsck.k9.service.MailService"); - i.setAction(ACTION_CHECK_MAIL); - PendingIntent pi = PendingIntent.getService(this, 0, i, 0); - - int shortestInterval = -1; - for (Account account : Preferences.getPreferences(this).getAccounts()) { - if (account.getAutomaticCheckIntervalMinutes() != -1 - && (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) { - shortestInterval = account.getAutomaticCheckIntervalMinutes(); - } - } - - if (shortestInterval == -1) { - alarmMgr.cancel(pi); - } - else { - alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() - + (shortestInterval * (60 * 1000)), pi); - } - } - - public IBinder onBind(Intent intent) { - return null; - } - - class Listener extends MessagingListener { - HashMap accountsWithNewMail = new HashMap(); - - @Override - public void checkMailStarted(Context context, Account account) { - accountsWithNewMail.clear(); - } - - @Override - public void checkMailFailed(Context context, Account account, String reason) { - reschedule(); - stopSelf(mStartId); - } - - @Override - public void synchronizeMailboxFinished( - Account account, - String folder, - int totalMessagesInMailbox, - int numNewMessages) { - if (account.isNotifyNewMail() && numNewMessages > 0) { - accountsWithNewMail.put(account, numNewMessages); - } - } - - @Override - public void checkMailFinished(Context context, Account account) { - NotificationManager notifMgr = (NotificationManager)context - .getSystemService(Context.NOTIFICATION_SERVICE); - - if (accountsWithNewMail.size() > 0) { - Notification notif = new Notification(R.drawable.stat_notify_email_generic, - getString(R.string.notification_new_title), System.currentTimeMillis()); - boolean vibrate = false; - String ringtone = null; - if (accountsWithNewMail.size() > 1) { - for (Account account1 : accountsWithNewMail.keySet()) { - if (account1.isVibrate()) vibrate = true; - ringtone = account1.getRingtone(); - } - Intent i = new Intent(context, Accounts.class); - PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0); - notif.setLatestEventInfo(context, getString(R.string.notification_new_title), - getString(R.string.notification_new_multi_account_fmt, - accountsWithNewMail.size()), pi); - } else { - Account account1 = accountsWithNewMail.keySet().iterator().next(); - int totalNewMails = accountsWithNewMail.get(account1); - Intent i = FolderMessageList.actionHandleAccountIntent(context, account1, k9.INBOX); - PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0); - notif.setLatestEventInfo(context, getString(R.string.notification_new_title), - getString(R.string.notification_new_one_account_fmt, totalNewMails, - account1.getDescription()), pi); - vibrate = account1.isVibrate(); - ringtone = account1.getRingtone(); - } - notif.defaults = Notification.DEFAULT_LIGHTS; - notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone); - if (vibrate) { - notif.defaults |= Notification.DEFAULT_VIBRATE; - } - notifMgr.notify(1, notif); - } - - reschedule(); - stopSelf(mStartId); - } - } -} diff --git a/src/org/apache/commons/io/CopyUtils.java b/src/org/apache/commons/io/CopyUtils.java deleted file mode 100644 index eab8307e7..000000000 --- a/src/org/apache/commons/io/CopyUtils.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.StringReader; -import java.io.Writer; - -/** - * This class provides static utility methods for buffered - * copying between sources (InputStream, Reader, - * String and byte[]) and destinations - * (OutputStream, Writer, String and - * byte[]). - *

- * Unless otherwise noted, these copy methods do not - * flush or close the streams. Often doing so would require making non-portable - * assumptions about the streams' origin and further use. This means that both - * streams' close() methods must be called after copying. if one - * omits this step, then the stream resources (sockets, file descriptors) are - * released when the associated Stream is garbage-collected. It is not a good - * idea to rely on this mechanism. For a good overview of the distinction - * between "memory management" and "resource management", see - * this - * UnixReview article. - *

- * For byte-to-char methods, a copy variant allows the encoding - * to be selected (otherwise the platform default is used). We would like to - * encourage you to always specify the encoding because relying on the platform - * default can lead to unexpected results. - *

copy methods that - * let you specify the buffer size because in modern VMs the impact on speed - * seems to be minimal. We're using a default buffer size of 4 KB. - *

- * The copy methods use an internal buffer when copying. It is - * therefore advisable not to deliberately wrap the stream arguments - * to the copy methods in Buffered* streams. For - * example, don't do the following: - *

- *  copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );
- *  
- * The rationale is as follows: - *

- * Imagine that an InputStream's read() is a very expensive operation, which - * would usually suggest wrapping in a BufferedInputStream. The - * BufferedInputStream works by issuing infrequent - * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the - * underlying InputStream, to fill an internal buffer, from which further - * read requests can inexpensively get their data (until the buffer - * runs out). - *

- * However, the copy methods do the same thing, keeping an - * internal buffer, populated by - * {@link InputStream#read(byte[] b, int off, int len)} requests. Having two - * buffers (or three if the destination stream is also buffered) is pointless, - * and the unnecessary buffer management hurts performance slightly (about 3%, - * according to some simple experiments). - *

- * Behold, intrepid explorers; a map of this class: - *

- *       Method      Input               Output          Dependency
- *       ------      -----               ------          -------
- * 1     copy        InputStream         OutputStream    (primitive)
- * 2     copy        Reader              Writer          (primitive)
- *
- * 3     copy        InputStream         Writer          2
- *
- * 4     copy        Reader              OutputStream    2
- *
- * 5     copy        String              OutputStream    2
- * 6     copy        String              Writer          (trivial)
- *
- * 7     copy        byte[]              Writer          3
- * 8     copy        byte[]              OutputStream    (trivial)
- * 
- *

- * Note that only the first two methods shuffle bytes; the rest use these - * two, or (if possible) copy using native Java copy methods. As there are - * method variants to specify the encoding, each row may - * correspond to up to 2 methods. - *

- * Origin of code: Excalibur. - * - * @author Peter Donald - * @author Jeff Turner - * @author Matthew Hawthorne - * @version $Id: CopyUtils.java 437680 2006-08-28 11:57:00Z scolebourne $ - * @deprecated Use IOUtils. Will be removed in 2.0. - * Methods renamed to IOUtils.write() or IOUtils.copy(). - * Null handling behaviour changed in IOUtils (null data does not - * throw NullPointerException). - */ -public class CopyUtils { - - /** - * The default size of the buffer. - */ - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - - /** - * Instances should NOT be constructed in standard programming. - */ - public CopyUtils() { } - - // ---------------------------------------------------------------- - // byte[] -> OutputStream - // ---------------------------------------------------------------- - - /** - * Copy bytes from a byte[] to an OutputStream. - * @param input the byte array to read from - * @param output the OutputStream to write to - * @throws IOException In case of an I/O problem - */ - public static void copy(byte[] input, OutputStream output) - throws IOException { - output.write(input); - } - - // ---------------------------------------------------------------- - // byte[] -> Writer - // ---------------------------------------------------------------- - - /** - * Copy and convert bytes from a byte[] to chars on a - * Writer. - * The platform's default encoding is used for the byte-to-char conversion. - * @param input the byte array to read from - * @param output the Writer to write to - * @throws IOException In case of an I/O problem - */ - public static void copy(byte[] input, Writer output) - throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream(input); - copy(in, output); - } - - - /** - * Copy and convert bytes from a byte[] to chars on a - * Writer, using the specified encoding. - * @param input the byte array to read from - * @param output the Writer to write to - * @param encoding The name of a supported character encoding. See the - * IANA - * Charset Registry for a list of valid encoding types. - * @throws IOException In case of an I/O problem - */ - public static void copy( - byte[] input, - Writer output, - String encoding) - throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream(input); - copy(in, output, encoding); - } - - - // ---------------------------------------------------------------- - // Core copy methods - // ---------------------------------------------------------------- - - /** - * Copy bytes from an InputStream to an - * OutputStream. - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @return the number of bytes copied - * @throws IOException In case of an I/O problem - */ - public static int copy( - InputStream input, - OutputStream output) - throws IOException { - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - int count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - // ---------------------------------------------------------------- - // Reader -> Writer - // ---------------------------------------------------------------- - - /** - * Copy chars from a Reader to a Writer. - * @param input the Reader to read from - * @param output the Writer to write to - * @return the number of characters copied - * @throws IOException In case of an I/O problem - */ - public static int copy( - Reader input, - Writer output) - throws IOException { - char[] buffer = new char[DEFAULT_BUFFER_SIZE]; - int count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - // ---------------------------------------------------------------- - // InputStream -> Writer - // ---------------------------------------------------------------- - - /** - * Copy and convert bytes from an InputStream to chars on a - * Writer. - * The platform's default encoding is used for the byte-to-char conversion. - * @param input the InputStream to read from - * @param output the Writer to write to - * @throws IOException In case of an I/O problem - */ - public static void copy( - InputStream input, - Writer output) - throws IOException { - InputStreamReader in = new InputStreamReader(input); - copy(in, output); - } - - /** - * Copy and convert bytes from an InputStream to chars on a - * Writer, using the specified encoding. - * @param input the InputStream to read from - * @param output the Writer to write to - * @param encoding The name of a supported character encoding. See the - * IANA - * Charset Registry for a list of valid encoding types. - * @throws IOException In case of an I/O problem - */ - public static void copy( - InputStream input, - Writer output, - String encoding) - throws IOException { - InputStreamReader in = new InputStreamReader(input, encoding); - copy(in, output); - } - - - // ---------------------------------------------------------------- - // Reader -> OutputStream - // ---------------------------------------------------------------- - - /** - * Serialize chars from a Reader to bytes on an - * OutputStream, and flush the OutputStream. - * @param input the Reader to read from - * @param output the OutputStream to write to - * @throws IOException In case of an I/O problem - */ - public static void copy( - Reader input, - OutputStream output) - throws IOException { - OutputStreamWriter out = new OutputStreamWriter(output); - copy(input, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - // ---------------------------------------------------------------- - // String -> OutputStream - // ---------------------------------------------------------------- - - /** - * Serialize chars from a String to bytes on an - * OutputStream, and - * flush the OutputStream. - * @param input the String to read from - * @param output the OutputStream to write to - * @throws IOException In case of an I/O problem - */ - public static void copy( - String input, - OutputStream output) - throws IOException { - StringReader in = new StringReader(input); - OutputStreamWriter out = new OutputStreamWriter(output); - copy(in, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - // ---------------------------------------------------------------- - // String -> Writer - // ---------------------------------------------------------------- - - /** - * Copy chars from a String to a Writer. - * @param input the String to read from - * @param output the Writer to write to - * @throws IOException In case of an I/O problem - */ - public static void copy(String input, Writer output) - throws IOException { - output.write(input); - } - -} diff --git a/src/org/apache/commons/io/DirectoryWalker.java b/src/org/apache/commons/io/DirectoryWalker.java deleted file mode 100644 index 9e564ae86..000000000 --- a/src/org/apache/commons/io/DirectoryWalker.java +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.util.Collection; - -import org.apache.commons.io.filefilter.FileFilterUtils; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.apache.commons.io.filefilter.TrueFileFilter; - -/** - * Abstract class that walks through a directory hierarchy and provides - * subclasses with convenient hooks to add specific behaviour. - *

- * This class operates with a {@link FileFilter} and maximum depth to - * limit the files and direcories visited. - * Commons IO supplies many common filter implementations in the - * filefilter package. - *

- * The following sections describe: - *

- * - * - *

1. Example Implementation

- * - * There are many possible extensions, for example, to delete all - * files and '.svn' directories, and return a list of deleted files: - *
- *  public class FileCleaner extends DirectoryWalker {
- *
- *    public FileCleaner() {
- *      super();
- *    }
- *
- *    public List clean(File startDirectory) {
- *      List results = new ArrayList();
- *      walk(startDirectory, results);
- *      return results;
- *    }
- *
- *    protected boolean handleDirectory(File directory, int depth, Collection results) {
- *      // delete svn directories and then skip
- *      if (".svn".equals(directory.getName())) {
- *        directory.delete();
- *        return false;
- *      } else {
- *        return true;
- *      }
- *
- *    }
- *
- *    protected void handleFile(File file, int depth, Collection results) {
- *      // delete file and add to list of deleted
- *      file.delete();
- *      results.add(file);
- *    }
- *  }
- * 
- * - * - *

2. Filter Example

- * - * Choosing which directories and files to process can be a key aspect - * of using this class. This information can be setup in three ways, - * via three different constructors. - *

- * The first option is to visit all directories and files. - * This is achieved via the no-args constructor. - *

- * The second constructor option is to supply a single {@link FileFilter} - * that describes the files and directories to visit. Care must be taken - * with this option as the same filter is used for both directories - * and files. - *

- * For example, if you wanted all directories which are not hidden - * and files which end in ".txt": - *

- *  public class FooDirectoryWalker extends DirectoryWalker {
- *    public FooDirectoryWalker(FileFilter filter) {
- *      super(filter, -1);
- *    }
- *  }
- *  
- *  // Build up the filters and create the walker
- *    // Create a filter for Non-hidden directories
- *    IOFileFilter fooDirFilter = 
- *        FileFilterUtils.andFileFilter(FileFilterUtils.directoryFileFilter,
- *                                      HiddenFileFilter.VISIBLE);
- *
- *    // Create a filter for Files ending in ".txt"
- *    IOFileFilter fooFileFilter = 
- *        FileFilterUtils.andFileFilter(FileFilterUtils.fileFileFilter,
- *                                      FileFilterUtils.suffixFileFilter(".txt"));
- *
- *    // Combine the directory and file filters using an OR condition
- *    java.io.FileFilter fooFilter = 
- *        FileFilterUtils.orFileFilter(fooDirFilter, fooFileFilter);
- *
- *    // Use the filter to construct a DirectoryWalker implementation
- *    FooDirectoryWalker walker = new FooDirectoryWalker(fooFilter);
- * 
- *

- * The third constructor option is to specify separate filters, one for - * directories and one for files. These are combined internally to form - * the correct FileFilter, something which is very easy to - * get wrong when attempted manually, particularly when trying to - * express constructs like 'any file in directories named docs'. - *

- * For example, if you wanted all directories which are not hidden - * and files which end in ".txt": - *

- *  public class FooDirectoryWalker extends DirectoryWalker {
- *    public FooDirectoryWalker(IOFileFilter dirFilter, IOFileFilter fileFilter) {
- *      super(dirFilter, fileFilter, -1);
- *    }
- *  }
- *  
- *  // Use the filters to construct the walker
- *  FooDirectoryWalker walker = new FooDirectoryWalker(
- *    HiddenFileFilter.VISIBLE,
- *    FileFilterUtils.suffixFileFilter(".txt"),
- *  );
- * 
- * This is much simpler than the previous example, and is why it is the preferred - * option for filtering. - * - * - *

3. Cancellation

- * - * The DirectoryWalker contains some of the logic required for cancel processing. - * Subclasses must complete the implementation. - *

- * What DirectoryWalker does provide for cancellation is: - *

    - *
  • {@link CancelException} which can be thrown in any of the - * lifecycle methods to stop processing.
  • - *
  • The walk() method traps thrown {@link CancelException} - * and calls the handleCancelled() method, providing - * a place for custom cancel processing.
  • - *
- *

- * Implementations need to provide: - *

    - *
  • The decision logic on whether to cancel processing or not.
  • - *
  • Constructing and throwing a {@link CancelException}.
  • - *
  • Custom cancel processing in the handleCancelled() method. - *
- *

- * Two possible scenarios are envisaged for cancellation: - *

    - *
  • 3.1 External / Mult-threaded - cancellation being - * decided/initiated by an external process.
  • - *
  • 3.2 Internal - cancellation being decided/initiated - * from within a DirectoryWalker implementation.
  • - *
- *

- * The following sections provide example implementations for these two different - * scenarios. - * - * - *

3.1 External / Multi-threaded

- * - * This example provides a public cancel() method that can be - * called by another thread to stop the processing. A typical example use-case - * would be a cancel button on a GUI. Calling this method sets a - * - * volatile flag to ensure it will work properly in a multi-threaded environment. - * The flag is returned by the handleIsCancelled() method, which - * will cause the walk to stop immediately. The handleCancelled() - * method will be the next, and last, callback method received once cancellation - * has occurred. - * - *
- *  public class FooDirectoryWalker extends DirectoryWalker {
- *
- *    private volatile boolean cancelled = false;
- *
- *    public void cancel() {
- *        cancelled = true;
- *    }
- *
- *    private void handleIsCancelled(File file, int depth, Collection results) {
- *        return cancelled;
- *    }
- *
- *    protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
- *        // implement processing required when a cancellation occurs
- *    }
- *  }
- * 
- * - * - *

3.2 Internal

- * - * This shows an example of how internal cancellation processing could be implemented. - * Note the decision logic and throwing a {@link CancelException} could be implemented - * in any of the lifecycle methods. - * - *
- *  public class BarDirectoryWalker extends DirectoryWalker {
- *
- *    protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
- *        // cancel if hidden directory
- *        if (directory.isHidden()) {
- *            throw new CancelException(file, depth);
- *        }
- *        return true;
- *    }
- *
- *    protected void handleFile(File file, int depth, Collection results) throws IOException {
- *        // cancel if read-only file
- *        if (!file.canWrite()) {
- *            throw new CancelException(file, depth);
- *        }
- *        results.add(file);
- *    }
- *
- *    protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
- *        // implement processing required when a cancellation occurs
- *    }
- *  }
- * 
- * - * @since Commons IO 1.3 - * @version $Revision: 424748 $ - */ -public abstract class DirectoryWalker { - - /** - * The file filter to use to filter files and directories. - */ - private final FileFilter filter; - /** - * The limit on the directory depth to walk. - */ - private final int depthLimit; - - /** - * Construct an instance with no filtering and unlimited depth. - */ - protected DirectoryWalker() { - this(null, -1); - } - - /** - * Construct an instance with a filter and limit the depth navigated to. - *

- * The filter controls which files and directories will be navigated to as - * part of the walk. The {@link FileFilterUtils} class is useful for combining - * various filters together. A null filter means that no - * filtering should occur and all files and directories will be visited. - * - * @param filter the filter to apply, null means visit all files - * @param depthLimit controls how deep the hierarchy is - * navigated to (less than 0 means unlimited) - */ - protected DirectoryWalker(FileFilter filter, int depthLimit) { - this.filter = filter; - this.depthLimit = depthLimit; - } - - /** - * Construct an instance with a directory and a file filter and an optional - * limit on the depth navigated to. - *

- * The filters control which files and directories will be navigated to as part - * of the walk. This constructor uses {@link FileFilterUtils#makeDirectoryOnly(IOFileFilter)} - * and {@link FileFilterUtils#makeFileOnly(IOFileFilter)} internally to combine the filters. - * A null filter means that no filtering should occur. - * - * @param directoryFilter the filter to apply to directories, null means visit all directories - * @param fileFilter the filter to apply to files, null means visit all files - * @param depthLimit controls how deep the hierarchy is - * navigated to (less than 0 means unlimited) - */ - protected DirectoryWalker(IOFileFilter directoryFilter, IOFileFilter fileFilter, int depthLimit) { - if (directoryFilter == null && fileFilter == null) { - this.filter = null; - } else { - directoryFilter = (directoryFilter != null ? directoryFilter : TrueFileFilter.TRUE); - fileFilter = (fileFilter != null ? fileFilter : TrueFileFilter.TRUE); - directoryFilter = FileFilterUtils.makeDirectoryOnly(directoryFilter); - fileFilter = FileFilterUtils.makeFileOnly(fileFilter); - this.filter = FileFilterUtils.orFileFilter(directoryFilter, fileFilter); - } - this.depthLimit = depthLimit; - } - - //----------------------------------------------------------------------- - /** - * Internal method that walks the directory hierarchy in a depth-first manner. - *

- * Users of this class do not need to call this method. This method will - * be called automatically by another (public) method on the specific subclass. - *

- * Writers of subclasses should call this method to start the directory walk. - * Once called, this method will emit events as it walks the hierarchy. - * The event methods have the prefix handle. - * - * @param startDirectory the directory to start from, not null - * @param results the collection of result objects, may be updated - * @throws NullPointerException if the start directory is null - * @throws IOException if an I/O Error occurs - */ - protected final void walk(File startDirectory, Collection results) throws IOException { - if (startDirectory == null) { - throw new NullPointerException("Start Directory is null"); - } - try { - handleStart(startDirectory, results); - walk(startDirectory, 0, results); - handleEnd(results); - } catch(CancelException cancel) { - handleCancelled(startDirectory, results, cancel); - } - } - - /** - * Main recursive method to examine the directory hierarchy. - * - * @param directory the directory to examine, not null - * @param depth the directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - private void walk(File directory, int depth, Collection results) throws IOException { - checkIfCancelled(directory, depth, results); - if (handleDirectory(directory, depth, results)) { - handleDirectoryStart(directory, depth, results); - int childDepth = depth + 1; - if (depthLimit < 0 || childDepth <= depthLimit) { - checkIfCancelled(directory, depth, results); - File[] childFiles = (filter == null ? directory.listFiles() : directory.listFiles(filter)); - if (childFiles == null) { - handleRestricted(directory, childDepth, results); - } else { - for (int i = 0; i < childFiles.length; i++) { - File childFile = childFiles[i]; - if (childFile.isDirectory()) { - walk(childFile, childDepth, results); - } else { - checkIfCancelled(childFile, childDepth, results); - handleFile(childFile, childDepth, results); - checkIfCancelled(childFile, childDepth, results); - } - } - } - } - handleDirectoryEnd(directory, depth, results); - } - checkIfCancelled(directory, depth, results); - } - - //----------------------------------------------------------------------- - /** - * Checks whether the walk has been cancelled by calling {@link #handleIsCancelled}, - * throwing a CancelException if it has. - *

- * Writers of subclasses should not normally call this method as it is called - * automatically by the walk of the tree. However, sometimes a single method, - * typically {@link #handleFile}, may take a long time to run. In that case, - * you may wish to check for cancellation by calling this method. - * - * @param file the current file being processed - * @param depth the current file level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected final void checkIfCancelled(File file, int depth, Collection results) throws IOException { - if (handleIsCancelled(file, depth, results)) { - throw new CancelException(file, depth); - } - } - - /** - * Overridable callback method invoked to determine if the entire walk - * operation should be immediately cancelled. - *

- * This method should be implemented by those subclasses that want to - * provide a public cancel() method available from another - * thread. The design pattern for the subclass should be as follows: - *

-     *  public class FooDirectoryWalker extends DirectoryWalker {
-     *    private volatile boolean cancelled = false;
-     *
-     *    public void cancel() {
-     *        cancelled = true;
-     *    }
-     *    private void handleIsCancelled(File file, int depth, Collection results) {
-     *        return cancelled;
-     *    }
-     *    protected void handleCancelled(File startDirectory,
-     *              Collection results, CancelException cancel) {
-     *        // implement processing required when a cancellation occurs
-     *    }
-     *  }
-     * 
- *

- * If this method returns true, then the directory walk is immediately - * cancelled. The next callback method will be {@link #handleCancelled}. - *

- * This implementation returns false. - * - * @param file the file or directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @return true if the walk has been cancelled - * @throws IOException if an I/O Error occurs - */ - protected boolean handleIsCancelled( - File file, int depth, Collection results) throws IOException { - // do nothing - overridable by subclass - return false; // not cancelled - } - - /** - * Overridable callback method invoked when the operation is cancelled. - * The file being processed when the cancellation occurred can be - * obtained from the exception. - *

- * This implementation just re-throws the {@link CancelException}. - * - * @param startDirectory the directory that the walk started from - * @param results the collection of result objects, may be updated - * @param cancel the exception throw to cancel further processing - * containing details at the point of cancellation. - * @throws IOException if an I/O Error occurs - */ - protected void handleCancelled(File startDirectory, Collection results, - CancelException cancel) throws IOException { - // re-throw exception - overridable by subclass - throw cancel; - } - - //----------------------------------------------------------------------- - /** - * Overridable callback method invoked at the start of processing. - *

- * This implementation does nothing. - * - * @param startDirectory the directory to start from - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected void handleStart(File startDirectory, Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked to determine if a directory should be processed. - *

- * This method returns a boolean to indicate if the directory should be examined or not. - * If you return false, the entire directory and any subdirectories will be skipped. - * Note that this functionality is in addition to the filtering by file filter. - *

- * This implementation does nothing and returns true. - * - * @param directory the current directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @return true to process this directory, false to skip this directory - * @throws IOException if an I/O Error occurs - */ - protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException { - // do nothing - overridable by subclass - return true; // process directory - } - - /** - * Overridable callback method invoked at the start of processing each directory. - *

- * This implementation does nothing. - * - * @param directory the current directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected void handleDirectoryStart(File directory, int depth, Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked for each (non-directory) file. - *

- * This implementation does nothing. - * - * @param file the current file being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected void handleFile(File file, int depth, Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked for each restricted directory. - *

- * This implementation does nothing. - * - * @param directory the restricted directory - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected void handleRestricted(File directory, int depth, Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked at the end of processing each directory. - *

- * This implementation does nothing. - * - * @param directory the directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected void handleDirectoryEnd(File directory, int depth, Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked at the end of processing. - *

- * This implementation does nothing. - * - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected void handleEnd(Collection results) throws IOException { - // do nothing - overridable by subclass - } - - //----------------------------------------------------------------------- - /** - * CancelException is thrown in DirectoryWalker to cancel the current - * processing. - */ - public static class CancelException extends IOException { - - /** Serialization id. */ - private static final long serialVersionUID = 1347339620135041008L; - - /** The file being processed when the exception was thrown. */ - private File file; - /** The file depth when the exception was thrown. */ - private int depth = -1; - - /** - * Constructs a CancelException with - * the file and depth when cancellation occurred. - * - * @param file the file when the operation was cancelled, may be null - * @param depth the depth when the operation was cancelled, may be null - */ - public CancelException(File file, int depth) { - this("Operation Cancelled", file, depth); - } - - /** - * Constructs a CancelException with - * an appropriate message and the file and depth when - * cancellation occurred. - * - * @param message the detail message - * @param file the file when the operation was cancelled - * @param depth the depth when the operation was cancelled - */ - public CancelException(String message, File file, int depth) { - super(message); - this.file = file; - this.depth = depth; - } - - /** - * Return the file when the operation was cancelled. - * - * @return the file when the operation was cancelled - */ - public File getFile() { - return file; - } - - /** - * Return the depth when the operation was cancelled. - * - * @return the depth when the operation was cancelled - */ - public int getDepth() { - return depth; - } - } -} diff --git a/src/org/apache/commons/io/EndianUtils.java b/src/org/apache/commons/io/EndianUtils.java deleted file mode 100644 index 810feac04..000000000 --- a/src/org/apache/commons/io/EndianUtils.java +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Utility code for dealing with different endian systems. - *

- * Different computer architectures adopt different conventions for - * byte ordering. In so-called "Little Endian" architectures (eg Intel), - * the low-order byte is stored in memory at the lowest address, and - * subsequent bytes at higher addresses. For "Big Endian" architectures - * (eg Motorola), the situation is reversed. - * This class helps you solve this incompatability. - *

- * Origin of code: Excalibur - * - * @author Peter Donald - * @version $Id: EndianUtils.java 539632 2007-05-18 23:37:59Z bayard $ - * @see org.apache.commons.io.input.SwappedDataInputStream - */ -public class EndianUtils { - - /** - * Instances should NOT be constructed in standard programming. - */ - public EndianUtils() { - super(); - } - - // ========================================== Swapping routines - - /** - * Converts a "short" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static short swapShort(short value) { - return (short) ( ( ( ( value >> 0 ) & 0xff ) << 8 ) + - ( ( ( value >> 8 ) & 0xff ) << 0 ) ); - } - - /** - * Converts a "int" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static int swapInteger(int value) { - return - ( ( ( value >> 0 ) & 0xff ) << 24 ) + - ( ( ( value >> 8 ) & 0xff ) << 16 ) + - ( ( ( value >> 16 ) & 0xff ) << 8 ) + - ( ( ( value >> 24 ) & 0xff ) << 0 ); - } - - /** - * Converts a "long" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static long swapLong(long value) { - return - ( ( ( value >> 0 ) & 0xff ) << 56 ) + - ( ( ( value >> 8 ) & 0xff ) << 48 ) + - ( ( ( value >> 16 ) & 0xff ) << 40 ) + - ( ( ( value >> 24 ) & 0xff ) << 32 ) + - ( ( ( value >> 32 ) & 0xff ) << 24 ) + - ( ( ( value >> 40 ) & 0xff ) << 16 ) + - ( ( ( value >> 48 ) & 0xff ) << 8 ) + - ( ( ( value >> 56 ) & 0xff ) << 0 ); - } - - /** - * Converts a "float" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static float swapFloat(float value) { - return Float.intBitsToFloat( swapInteger( Float.floatToIntBits( value ) ) ); - } - - /** - * Converts a "double" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static double swapDouble(double value) { - return Double.longBitsToDouble( swapLong( Double.doubleToLongBits( value ) ) ); - } - - // ========================================== Swapping read/write routines - - /** - * Writes a "short" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedShort(byte[] data, int offset, short value) { - data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff ); - data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff ); - } - - /** - * Reads a "short" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static short readSwappedShort(byte[] data, int offset) { - return (short)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) ); - } - - /** - * Reads an unsigned short (16-bit) value from a byte array at a given - * offset. The value is converted to the opposed endian system while - * reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static int readSwappedUnsignedShort(byte[] data, int offset) { - return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) ); - } - - /** - * Writes a "int" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedInteger(byte[] data, int offset, int value) { - data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff ); - data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff ); - data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff ); - data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff ); - } - - /** - * Reads a "int" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static int readSwappedInteger(byte[] data, int offset) { - return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) + - ( ( data[ offset + 2 ] & 0xff ) << 16 ) + - ( ( data[ offset + 3 ] & 0xff ) << 24 ) ); - } - - /** - * Reads an unsigned integer (32-bit) value from a byte array at a given - * offset. The value is converted to the opposed endian system while - * reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static long readSwappedUnsignedInteger(byte[] data, int offset) { - long low = ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) + - ( ( data[ offset + 2 ] & 0xff ) << 16 ) ); - - long high = data[ offset + 3 ] & 0xff; - - return (high << 24) + (0xffffffffL & low); - } - - /** - * Writes a "long" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedLong(byte[] data, int offset, long value) { - data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff ); - data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff ); - data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff ); - data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff ); - data[ offset + 4 ] = (byte)( ( value >> 32 ) & 0xff ); - data[ offset + 5 ] = (byte)( ( value >> 40 ) & 0xff ); - data[ offset + 6 ] = (byte)( ( value >> 48 ) & 0xff ); - data[ offset + 7 ] = (byte)( ( value >> 56 ) & 0xff ); - } - - /** - * Reads a "long" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static long readSwappedLong(byte[] data, int offset) { - long low = - ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) + - ( ( data[ offset + 2 ] & 0xff ) << 16 ) + - ( ( data[ offset + 3 ] & 0xff ) << 24 ); - long high = - ( ( data[ offset + 4 ] & 0xff ) << 0 ) + - ( ( data[ offset + 5 ] & 0xff ) << 8 ) + - ( ( data[ offset + 6 ] & 0xff ) << 16 ) + - ( ( data[ offset + 7 ] & 0xff ) << 24 ); - return (high << 32) + (0xffffffffL & low); - } - - /** - * Writes a "float" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedFloat(byte[] data, int offset, float value) { - writeSwappedInteger( data, offset, Float.floatToIntBits( value ) ); - } - - /** - * Reads a "float" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static float readSwappedFloat(byte[] data, int offset) { - return Float.intBitsToFloat( readSwappedInteger( data, offset ) ); - } - - /** - * Writes a "double" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedDouble(byte[] data, int offset, double value) { - writeSwappedLong( data, offset, Double.doubleToLongBits( value ) ); - } - - /** - * Reads a "double" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static double readSwappedDouble(byte[] data, int offset) { - return Double.longBitsToDouble( readSwappedLong( data, offset ) ); - } - - /** - * Writes a "short" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedShort(OutputStream output, short value) - throws IOException - { - output.write( (byte)( ( value >> 0 ) & 0xff ) ); - output.write( (byte)( ( value >> 8 ) & 0xff ) ); - } - - /** - * Reads a "short" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static short readSwappedShort(InputStream input) - throws IOException - { - return (short)( ( ( read( input ) & 0xff ) << 0 ) + - ( ( read( input ) & 0xff ) << 8 ) ); - } - - /** - * Reads a unsigned short (16-bit) from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static int readSwappedUnsignedShort(InputStream input) - throws IOException - { - int value1 = read( input ); - int value2 = read( input ); - - return ( ( ( value1 & 0xff ) << 0 ) + - ( ( value2 & 0xff ) << 8 ) ); - } - - /** - * Writes a "int" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedInteger(OutputStream output, int value) - throws IOException - { - output.write( (byte)( ( value >> 0 ) & 0xff ) ); - output.write( (byte)( ( value >> 8 ) & 0xff ) ); - output.write( (byte)( ( value >> 16 ) & 0xff ) ); - output.write( (byte)( ( value >> 24 ) & 0xff ) ); - } - - /** - * Reads a "int" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static int readSwappedInteger(InputStream input) - throws IOException - { - int value1 = read( input ); - int value2 = read( input ); - int value3 = read( input ); - int value4 = read( input ); - - return ( ( value1 & 0xff ) << 0 ) + - ( ( value2 & 0xff ) << 8 ) + - ( ( value3 & 0xff ) << 16 ) + - ( ( value4 & 0xff ) << 24 ); - } - - /** - * Reads a unsigned integer (32-bit) from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static long readSwappedUnsignedInteger(InputStream input) - throws IOException - { - int value1 = read( input ); - int value2 = read( input ); - int value3 = read( input ); - int value4 = read( input ); - - long low = ( ( ( value1 & 0xff ) << 0 ) + - ( ( value2 & 0xff ) << 8 ) + - ( ( value3 & 0xff ) << 16 ) ); - - long high = value4 & 0xff; - - return (high << 24) + (0xffffffffL & low); - } - - /** - * Writes a "long" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedLong(OutputStream output, long value) - throws IOException - { - output.write( (byte)( ( value >> 0 ) & 0xff ) ); - output.write( (byte)( ( value >> 8 ) & 0xff ) ); - output.write( (byte)( ( value >> 16 ) & 0xff ) ); - output.write( (byte)( ( value >> 24 ) & 0xff ) ); - output.write( (byte)( ( value >> 32 ) & 0xff ) ); - output.write( (byte)( ( value >> 40 ) & 0xff ) ); - output.write( (byte)( ( value >> 48 ) & 0xff ) ); - output.write( (byte)( ( value >> 56 ) & 0xff ) ); - } - - /** - * Reads a "long" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static long readSwappedLong(InputStream input) - throws IOException - { - byte[] bytes = new byte[8]; - for ( int i=0; i<8; i++ ) { - bytes[i] = (byte) read( input ); - } - return readSwappedLong( bytes, 0 ); - } - - /** - * Writes a "float" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedFloat(OutputStream output, float value) - throws IOException - { - writeSwappedInteger( output, Float.floatToIntBits( value ) ); - } - - /** - * Reads a "float" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static float readSwappedFloat(InputStream input) - throws IOException - { - return Float.intBitsToFloat( readSwappedInteger( input ) ); - } - - /** - * Writes a "double" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedDouble(OutputStream output, double value) - throws IOException - { - writeSwappedLong( output, Double.doubleToLongBits( value ) ); - } - - /** - * Reads a "double" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static double readSwappedDouble(InputStream input) - throws IOException - { - return Double.longBitsToDouble( readSwappedLong( input ) ); - } - - /** - * Reads the next byte from the input stream. - * @param input the stream - * @return the byte - * @throws IOException if the end of file is reached - */ - private static int read(InputStream input) - throws IOException - { - int value = input.read(); - - if( -1 == value ) { - throw new EOFException( "Unexpected EOF reached" ); - } - - return value; - } -} diff --git a/src/org/apache/commons/io/FileCleaner.java b/src/org/apache/commons/io/FileCleaner.java deleted file mode 100644 index 59c2f4109..000000000 --- a/src/org/apache/commons/io/FileCleaner.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; - -/** - * Keeps track of files awaiting deletion, and deletes them when an associated - * marker object is reclaimed by the garbage collector. - *

- * This utility creates a background thread to handle file deletion. - * Each file to be deleted is registered with a handler object. - * When the handler object is garbage collected, the file is deleted. - *

- * In an environment with multiple class loaders (a servlet container, for - * example), you should consider stopping the background thread if it is no - * longer needed. This is done by invoking the method - * {@link #exitWhenFinished}, typically in - * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar. - * - * @author Noel Bergman - * @author Martin Cooper - * @version $Id: FileCleaner.java 553012 2007-07-03 23:01:07Z ggregory $ - * @deprecated Use {@link FileCleaningTracker} - */ -public class FileCleaner { - /** - * The instance to use for the deprecated, static methods. - */ - static final FileCleaningTracker theInstance = new FileCleaningTracker(); - - //----------------------------------------------------------------------- - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the file is null - * @deprecated Use {@link FileCleaningTracker#track(File, Object)}. - */ - public static void track(File file, Object marker) { - theInstance.track(file, marker); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The speified deletion strategy is used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the file is null - * @deprecated Use {@link FileCleaningTracker#track(File, Object, FileDeleteStrategy)}. - */ - public static void track(File file, Object marker, FileDeleteStrategy deleteStrategy) { - theInstance.track(file, marker, deleteStrategy); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the path is null - * @deprecated Use {@link FileCleaningTracker#track(String, Object)}. - */ - public static void track(String path, Object marker) { - theInstance.track(path, marker); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The speified deletion strategy is used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the path is null - * @deprecated Use {@link FileCleaningTracker#track(String, Object, FileDeleteStrategy)}. - */ - public static void track(String path, Object marker, FileDeleteStrategy deleteStrategy) { - theInstance.track(path, marker, deleteStrategy); - } - - //----------------------------------------------------------------------- - /** - * Retrieve the number of files currently being tracked, and therefore - * awaiting deletion. - * - * @return the number of files being tracked - * @deprecated Use {@link FileCleaningTracker#getTrackCount()}. - */ - public static int getTrackCount() { - return theInstance.getTrackCount(); - } - - /** - * Call this method to cause the file cleaner thread to terminate when - * there are no more objects being tracked for deletion. - *

- * In a simple environment, you don't need this method as the file cleaner - * thread will simply exit when the JVM exits. In a more complex environment, - * with multiple class loaders (such as an application server), you should be - * aware that the file cleaner thread will continue running even if the class - * loader it was started from terminates. This can consitute a memory leak. - *

- * For example, suppose that you have developed a web application, which - * contains the commons-io jar file in your WEB-INF/lib directory. In other - * words, the FileCleaner class is loaded through the class loader of your - * web application. If the web application is terminated, but the servlet - * container is still running, then the file cleaner thread will still exist, - * posing a memory leak. - *

- * This method allows the thread to be terminated. Simply call this method - * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}. - * One called, no new objects can be tracked by the file cleaner. - * @deprecated Use {@link FileCleaningTracker#exitWhenFinished()}. - */ - public static synchronized void exitWhenFinished() { - theInstance.exitWhenFinished(); - } - - /** - * Returns the singleton instance, which is used by the deprecated, static methods. - * This is mainly useful for code, which wants to support the new - * {@link FileCleaningTracker} class while maintain compatibility with the - * deprecated {@link FileCleaner}. - * - * @return the singleton instance - */ - public static FileCleaningTracker getInstance() { - return theInstance; - } -} diff --git a/src/org/apache/commons/io/FileCleaningTracker.java b/src/org/apache/commons/io/FileCleaningTracker.java deleted file mode 100644 index ea976d60a..000000000 --- a/src/org/apache/commons/io/FileCleaningTracker.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.lang.ref.PhantomReference; -import java.lang.ref.ReferenceQueue; -import java.util.Collection; -import java.util.Vector; - -/** - * Keeps track of files awaiting deletion, and deletes them when an associated - * marker object is reclaimed by the garbage collector. - *

- * This utility creates a background thread to handle file deletion. - * Each file to be deleted is registered with a handler object. - * When the handler object is garbage collected, the file is deleted. - *

- * In an environment with multiple class loaders (a servlet container, for - * example), you should consider stopping the background thread if it is no - * longer needed. This is done by invoking the method - * {@link #exitWhenFinished}, typically in - * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar. - * - * @author Noel Bergman - * @author Martin Cooper - * @version $Id: FileCleaner.java 490987 2006-12-29 12:11:48Z scolebourne $ - */ -public class FileCleaningTracker { - /** - * Queue of Tracker instances being watched. - */ - ReferenceQueue /* Tracker */ q = new ReferenceQueue(); - /** - * Collection of Tracker instances in existence. - */ - final Collection /* Tracker */ trackers = new Vector(); // synchronized - /** - * Whether to terminate the thread when the tracking is complete. - */ - volatile boolean exitWhenFinished = false; - /** - * The thread that will clean up registered files. - */ - Thread reaper; - - //----------------------------------------------------------------------- - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the file is null - */ - public void track(File file, Object marker) { - track(file, marker, (FileDeleteStrategy) null); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The speified deletion strategy is used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the file is null - */ - public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) { - if (file == null) { - throw new NullPointerException("The file must not be null"); - } - addTracker(file.getPath(), marker, deleteStrategy); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the path is null - */ - public void track(String path, Object marker) { - track(path, marker, (FileDeleteStrategy) null); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The speified deletion strategy is used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the path is null - */ - public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) { - if (path == null) { - throw new NullPointerException("The path must not be null"); - } - addTracker(path, marker, deleteStrategy); - } - - /** - * Adds a tracker to the list of trackers. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - */ - private synchronized void addTracker(String path, Object marker, FileDeleteStrategy deleteStrategy) { - // synchronized block protects reaper - if (exitWhenFinished) { - throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called"); - } - if (reaper == null) { - reaper = new Reaper(); - reaper.start(); - } - trackers.add(new Tracker(path, deleteStrategy, marker, q)); - } - - //----------------------------------------------------------------------- - /** - * Retrieve the number of files currently being tracked, and therefore - * awaiting deletion. - * - * @return the number of files being tracked - */ - public int getTrackCount() { - return trackers.size(); - } - - /** - * Call this method to cause the file cleaner thread to terminate when - * there are no more objects being tracked for deletion. - *

- * In a simple environment, you don't need this method as the file cleaner - * thread will simply exit when the JVM exits. In a more complex environment, - * with multiple class loaders (such as an application server), you should be - * aware that the file cleaner thread will continue running even if the class - * loader it was started from terminates. This can consitute a memory leak. - *

- * For example, suppose that you have developed a web application, which - * contains the commons-io jar file in your WEB-INF/lib directory. In other - * words, the FileCleaner class is loaded through the class loader of your - * web application. If the web application is terminated, but the servlet - * container is still running, then the file cleaner thread will still exist, - * posing a memory leak. - *

- * This method allows the thread to be terminated. Simply call this method - * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}. - * One called, no new objects can be tracked by the file cleaner. - */ - public synchronized void exitWhenFinished() { - // synchronized block protects reaper - exitWhenFinished = true; - if (reaper != null) { - synchronized (reaper) { - reaper.interrupt(); - } - } - } - - //----------------------------------------------------------------------- - /** - * The reaper thread. - */ - private final class Reaper extends Thread { - /** Construct a new Reaper */ - Reaper() { - super("File Reaper"); - setPriority(Thread.MAX_PRIORITY); - setDaemon(true); - } - - /** - * Run the reaper thread that will delete files as their associated - * marker objects are reclaimed by the garbage collector. - */ - public void run() { - // thread exits when exitWhenFinished is true and there are no more tracked objects - while (exitWhenFinished == false || trackers.size() > 0) { - Tracker tracker = null; - try { - // Wait for a tracker to remove. - tracker = (Tracker) q.remove(); - } catch (Exception e) { - continue; - } - if (tracker != null) { - tracker.delete(); - tracker.clear(); - trackers.remove(tracker); - } - } - } - } - - //----------------------------------------------------------------------- - /** - * Inner class which acts as the reference for a file pending deletion. - */ - private static final class Tracker extends PhantomReference { - - /** - * The full path to the file being tracked. - */ - private final String path; - /** - * The strategy for deleting files. - */ - private final FileDeleteStrategy deleteStrategy; - - /** - * Constructs an instance of this class from the supplied parameters. - * - * @param path the full path to the file to be tracked, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @param marker the marker object used to track the file, not null - * @param queue the queue on to which the tracker will be pushed, not null - */ - Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue queue) { - super(marker, queue); - this.path = path; - this.deleteStrategy = (deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy); - } - - /** - * Deletes the file associated with this tracker instance. - * - * @return true if the file was deleted successfully; - * false otherwise. - */ - public boolean delete() { - return deleteStrategy.deleteQuietly(new File(path)); - } - } - -} diff --git a/src/org/apache/commons/io/FileDeleteStrategy.java b/src/org/apache/commons/io/FileDeleteStrategy.java deleted file mode 100644 index 8b6b4b9aa..000000000 --- a/src/org/apache/commons/io/FileDeleteStrategy.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.io.IOException; - -/** - * Strategy for deleting files. - *

- * There is more than one way to delete a file. - * You may want to limit access to certain directories, to only delete - * directories if they are empty, or maybe to force deletion. - *

- * This class captures the strategy to use and is designed for user subclassing. - * - * @author Stephen Colebourne - * @version $Id: FileDeleteStrategy.java 453903 2006-10-07 13:47:06Z scolebourne $ - * @since Commons IO 1.3 - */ -public class FileDeleteStrategy { - - /** - * The singleton instance for normal file deletion, which does not permit - * the deletion of directories that are not empty. - */ - public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal"); - /** - * The singleton instance for forced file deletion, which always deletes, - * even if the file represents a non-empty directory. - */ - public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy(); - - /** The name of the strategy. */ - private final String name; - - //----------------------------------------------------------------------- - /** - * Restricted constructor. - * - * @param name the name by which the strategy is known - */ - protected FileDeleteStrategy(String name) { - this.name = name; - } - - //----------------------------------------------------------------------- - /** - * Deletes the file object, which may be a file or a directory. - * All IOExceptions are caught and false returned instead. - * If the file does not exist or is null, true is returned. - *

- * Subclass writers should override {@link #doDelete(File)}, not this method. - * - * @param fileToDelete the file to delete, null returns true - * @return true if the file was deleted, or there was no such file - */ - public boolean deleteQuietly(File fileToDelete) { - if (fileToDelete == null || fileToDelete.exists() == false) { - return true; - } - try { - return doDelete(fileToDelete); - } catch (IOException ex) { - return false; - } - } - - /** - * Deletes the file object, which may be a file or a directory. - * If the file does not exist, the method just returns. - *

- * Subclass writers should override {@link #doDelete(File)}, not this method. - * - * @param fileToDelete the file to delete, not null - * @throws NullPointerException if the file is null - * @throws IOException if an error occurs during file deletion - */ - public void delete(File fileToDelete) throws IOException { - if (fileToDelete.exists() && doDelete(fileToDelete) == false) { - throw new IOException("Deletion failed: " + fileToDelete); - } - } - - /** - * Actually deletes the file object, which may be a file or a directory. - *

- * This method is designed for subclasses to override. - * The implementation may return either false or an IOException - * when deletion fails. The {@link #delete(File)} and {@link #deleteQuietly(File)} - * methods will handle either response appropriately. - * A check has been made to ensure that the file will exist. - *

- * This implementation uses {@link File#delete()}. - * - * @param fileToDelete the file to delete, exists, not null - * @return true if the file was deleteds - * @throws NullPointerException if the file is null - * @throws IOException if an error occurs during file deletion - */ - protected boolean doDelete(File fileToDelete) throws IOException { - return fileToDelete.delete(); - } - - //----------------------------------------------------------------------- - /** - * Gets a string describing the delete strategy. - * - * @return a string describing the delete strategy - */ - public String toString() { - return "FileDeleteStrategy[" + name + "]"; - } - - //----------------------------------------------------------------------- - /** - * Force file deletion strategy. - */ - static class ForceFileDeleteStrategy extends FileDeleteStrategy { - /** Default Constructor */ - ForceFileDeleteStrategy() { - super("Force"); - } - - /** - * Deletes the file object. - *

- * This implementation uses FileUtils.forceDelete() - * if the file exists. - * - * @param fileToDelete the file to delete, not null - * @return Always returns true - * @throws NullPointerException if the file is null - * @throws IOException if an error occurs during file deletion - */ - protected boolean doDelete(File fileToDelete) throws IOException { - FileUtils.forceDelete(fileToDelete); - return true; - } - } - -} diff --git a/src/org/apache/commons/io/FileSystemUtils.java b/src/org/apache/commons/io/FileSystemUtils.java deleted file mode 100644 index a29dba439..000000000 --- a/src/org/apache/commons/io/FileSystemUtils.java +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.StringTokenizer; - -/** - * General File System utilities. - *

- * This class provides static utility methods for general file system - * functions not provided via the JDK {@link java.io.File File} class. - *

- * The current functions provided are: - *

    - *
  • Get the free space on a drive - *
- * - * @author Frank W. Zammetti - * @author Stephen Colebourne - * @author Thomas Ledoux - * @author James Urie - * @author Magnus Grimsell - * @author Thomas Ledoux - * @version $Id: FileSystemUtils.java 453889 2006-10-07 11:56:25Z scolebourne $ - * @since Commons IO 1.1 - */ -public class FileSystemUtils { - - /** Singleton instance, used mainly for testing. */ - private static final FileSystemUtils INSTANCE = new FileSystemUtils(); - - /** Operating system state flag for error. */ - private static final int INIT_PROBLEM = -1; - /** Operating system state flag for neither Unix nor Windows. */ - private static final int OTHER = 0; - /** Operating system state flag for Windows. */ - private static final int WINDOWS = 1; - /** Operating system state flag for Unix. */ - private static final int UNIX = 2; - /** Operating system state flag for Posix flavour Unix. */ - private static final int POSIX_UNIX = 3; - - /** The operating system flag. */ - private static final int OS; - static { - int os = OTHER; - try { - String osName = System.getProperty("os.name"); - if (osName == null) { - throw new IOException("os.name not found"); - } - osName = osName.toLowerCase(); - // match - if (osName.indexOf("windows") != -1) { - os = WINDOWS; - } else if (osName.indexOf("linux") != -1 || - osName.indexOf("sun os") != -1 || - osName.indexOf("sunos") != -1 || - osName.indexOf("solaris") != -1 || - osName.indexOf("mpe/ix") != -1 || - osName.indexOf("freebsd") != -1 || - osName.indexOf("irix") != -1 || - osName.indexOf("digital unix") != -1 || - osName.indexOf("unix") != -1 || - osName.indexOf("mac os x") != -1) { - os = UNIX; - } else if (osName.indexOf("hp-ux") != -1 || - osName.indexOf("aix") != -1) { - os = POSIX_UNIX; - } else { - os = OTHER; - } - - } catch (Exception ex) { - os = INIT_PROBLEM; - } - OS = os; - } - - /** - * Instances should NOT be constructed in standard programming. - */ - public FileSystemUtils() { - super(); - } - - //----------------------------------------------------------------------- - /** - * Returns the free space on a drive or volume by invoking - * the command line. - * This method does not normalize the result, and typically returns - * bytes on Windows, 512 byte units on OS X and kilobytes on Unix. - * As this is not very useful, this method is deprecated in favour - * of {@link #freeSpaceKb(String)} which returns a result in kilobytes. - *

- * Note that some OS's are NOT currently supported, including OS/390, - * OpenVMS and and SunOS 5. (SunOS is supported by freeSpaceKb.) - *

-     * FileSystemUtils.freeSpace("C:");       // Windows
-     * FileSystemUtils.freeSpace("/volume");  // *nix
-     * 
- * The free space is calculated via the command line. - * It uses 'dir /-c' on Windows and 'df' on *nix. - * - * @param path the path to get free space for, not null, not empty on Unix - * @return the amount of free drive space on the drive or volume - * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - * @since Commons IO 1.1, enhanced OS support in 1.2 and 1.3 - * @deprecated Use freeSpaceKb(String) - * Deprecated from 1.3, may be removed in 2.0 - */ - public static long freeSpace(String path) throws IOException { - return INSTANCE.freeSpaceOS(path, OS, false); - } - - //----------------------------------------------------------------------- - /** - * Returns the free space on a drive or volume in kilobytes by invoking - * the command line. - *
-     * FileSystemUtils.freeSpaceKb("C:");       // Windows
-     * FileSystemUtils.freeSpaceKb("/volume");  // *nix
-     * 
- * The free space is calculated via the command line. - * It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix. - *

- * In order to work, you must be running Windows, or have a implementation of - * Unix df that supports GNU format when passed -k (or -kP). If you are going - * to rely on this code, please check that it works on your OS by running - * some simple tests to compare the command line with the output from this class. - * If your operating system isn't supported, please raise a JIRA call detailing - * the exact result from df -k and as much other detail as possible, thanks. - * - * @param path the path to get free space for, not null, not empty on Unix - * @return the amount of free drive space on the drive or volume in kilobytes - * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - * @since Commons IO 1.2, enhanced OS support in 1.3 - */ - public static long freeSpaceKb(String path) throws IOException { - return INSTANCE.freeSpaceOS(path, OS, true); - } - - //----------------------------------------------------------------------- - /** - * Returns the free space on a drive or volume in a cross-platform manner. - * Note that some OS's are NOT currently supported, including OS/390. - *

-     * FileSystemUtils.freeSpace("C:");  // Windows
-     * FileSystemUtils.freeSpace("/volume");  // *nix
-     * 
- * The free space is calculated via the command line. - * It uses 'dir /-c' on Windows and 'df' on *nix. - * - * @param path the path to get free space for, not null, not empty on Unix - * @param os the operating system code - * @param kb whether to normalize to kilobytes - * @return the amount of free drive space on the drive or volume - * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - */ - long freeSpaceOS(String path, int os, boolean kb) throws IOException { - if (path == null) { - throw new IllegalArgumentException("Path must not be empty"); - } - switch (os) { - case WINDOWS: - return (kb ? freeSpaceWindows(path) / 1024 : freeSpaceWindows(path)); - case UNIX: - return freeSpaceUnix(path, kb, false); - case POSIX_UNIX: - return freeSpaceUnix(path, kb, true); - case OTHER: - throw new IllegalStateException("Unsupported operating system"); - default: - throw new IllegalStateException( - "Exception caught when determining operating system"); - } - } - - //----------------------------------------------------------------------- - /** - * Find free space on the Windows platform using the 'dir' command. - * - * @param path the path to get free space for, including the colon - * @return the amount of free drive space on the drive - * @throws IOException if an error occurs - */ - long freeSpaceWindows(String path) throws IOException { - path = FilenameUtils.normalize(path); - if (path.length() > 2 && path.charAt(1) == ':') { - path = path.substring(0, 2); // seems to make it work - } - - // build and run the 'dir' command - String[] cmdAttribs = new String[] {"cmd.exe", "/C", "dir /-c " + path}; - - // read in the output of the command to an ArrayList - List lines = performCommand(cmdAttribs, Integer.MAX_VALUE); - - // now iterate over the lines we just read and find the LAST - // non-empty line (the free space bytes should be in the last element - // of the ArrayList anyway, but this will ensure it works even if it's - // not, still assuming it is on the last non-blank line) - for (int i = lines.size() - 1; i >= 0; i--) { - String line = (String) lines.get(i); - if (line.length() > 0) { - return parseDir(line, path); - } - } - // all lines are blank - throw new IOException( - "Command line 'dir /-c' did not return any info " + - "for path '" + path + "'"); - } - - /** - * Parses the Windows dir response last line - * - * @param line the line to parse - * @param path the path that was sent - * @return the number of bytes - * @throws IOException if an error occurs - */ - long parseDir(String line, String path) throws IOException { - // read from the end of the line to find the last numeric - // character on the line, then continue until we find the first - // non-numeric character, and everything between that and the last - // numeric character inclusive is our free space bytes count - int bytesStart = 0; - int bytesEnd = 0; - int j = line.length() - 1; - innerLoop1: while (j >= 0) { - char c = line.charAt(j); - if (Character.isDigit(c)) { - // found the last numeric character, this is the end of - // the free space bytes count - bytesEnd = j + 1; - break innerLoop1; - } - j--; - } - innerLoop2: while (j >= 0) { - char c = line.charAt(j); - if (!Character.isDigit(c) && c != ',' && c != '.') { - // found the next non-numeric character, this is the - // beginning of the free space bytes count - bytesStart = j + 1; - break innerLoop2; - } - j--; - } - if (j < 0) { - throw new IOException( - "Command line 'dir /-c' did not return valid info " + - "for path '" + path + "'"); - } - - // remove commas and dots in the bytes count - StringBuffer buf = new StringBuffer(line.substring(bytesStart, bytesEnd)); - for (int k = 0; k < buf.length(); k++) { - if (buf.charAt(k) == ',' || buf.charAt(k) == '.') { - buf.deleteCharAt(k--); - } - } - return parseBytes(buf.toString(), path); - } - - //----------------------------------------------------------------------- - /** - * Find free space on the *nix platform using the 'df' command. - * - * @param path the path to get free space for - * @param kb whether to normalize to kilobytes - * @param posix whether to use the posix standard format flag - * @return the amount of free drive space on the volume - * @throws IOException if an error occurs - */ - long freeSpaceUnix(String path, boolean kb, boolean posix) throws IOException { - if (path.length() == 0) { - throw new IllegalArgumentException("Path must not be empty"); - } - path = FilenameUtils.normalize(path); - - // build and run the 'dir' command - String flags = "-"; - if (kb) { - flags += "k"; - } - if (posix) { - flags += "P"; - } - String[] cmdAttribs = - (flags.length() > 1 ? new String[] {"df", flags, path} : new String[] {"df", path}); - - // perform the command, asking for up to 3 lines (header, interesting, overflow) - List lines = performCommand(cmdAttribs, 3); - if (lines.size() < 2) { - // unknown problem, throw exception - throw new IOException( - "Command line 'df' did not return info as expected " + - "for path '" + path + "'- response was " + lines); - } - String line2 = (String) lines.get(1); // the line we're interested in - - // Now, we tokenize the string. The fourth element is what we want. - StringTokenizer tok = new StringTokenizer(line2, " "); - if (tok.countTokens() < 4) { - // could be long Filesystem, thus data on third line - if (tok.countTokens() == 1 && lines.size() >= 3) { - String line3 = (String) lines.get(2); // the line may be interested in - tok = new StringTokenizer(line3, " "); - } else { - throw new IOException( - "Command line 'df' did not return data as expected " + - "for path '" + path + "'- check path is valid"); - } - } else { - tok.nextToken(); // Ignore Filesystem - } - tok.nextToken(); // Ignore 1K-blocks - tok.nextToken(); // Ignore Used - String freeSpace = tok.nextToken(); - return parseBytes(freeSpace, path); - } - - //----------------------------------------------------------------------- - /** - * Parses the bytes from a string. - * - * @param freeSpace the free space string - * @param path the path - * @return the number of bytes - * @throws IOException if an error occurs - */ - long parseBytes(String freeSpace, String path) throws IOException { - try { - long bytes = Long.parseLong(freeSpace); - if (bytes < 0) { - throw new IOException( - "Command line 'df' did not find free space in response " + - "for path '" + path + "'- check path is valid"); - } - return bytes; - - } catch (NumberFormatException ex) { - throw new IOException( - "Command line 'df' did not return numeric data as expected " + - "for path '" + path + "'- check path is valid"); - } - } - - //----------------------------------------------------------------------- - /** - * Performs the os command. - * - * @param cmdAttribs the command line parameters - * @param max The maximum limit for the lines returned - * @return the parsed data - * @throws IOException if an error occurs - */ - List performCommand(String[] cmdAttribs, int max) throws IOException { - // this method does what it can to avoid the 'Too many open files' error - // based on trial and error and these links: - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4784692 - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4801027 - // http://forum.java.sun.com/thread.jspa?threadID=533029&messageID=2572018 - // however, its still not perfect as the JDK support is so poor - // (see commond-exec or ant for a better multi-threaded multi-os solution) - - List lines = new ArrayList(20); - Process proc = null; - InputStream in = null; - OutputStream out = null; - InputStream err = null; - BufferedReader inr = null; - try { - proc = openProcess(cmdAttribs); - in = proc.getInputStream(); - out = proc.getOutputStream(); - err = proc.getErrorStream(); - inr = new BufferedReader(new InputStreamReader(in)); - String line = inr.readLine(); - while (line != null && lines.size() < max) { - line = line.toLowerCase().trim(); - lines.add(line); - line = inr.readLine(); - } - - proc.waitFor(); - if (proc.exitValue() != 0) { - // os command problem, throw exception - throw new IOException( - "Command line returned OS error code '" + proc.exitValue() + - "' for command " + Arrays.asList(cmdAttribs)); - } - if (lines.size() == 0) { - // unknown problem, throw exception - throw new IOException( - "Command line did not return any info " + - "for command " + Arrays.asList(cmdAttribs)); - } - return lines; - - } catch (InterruptedException ex) { - throw new IOException( - "Command line threw an InterruptedException '" + ex.getMessage() + - "' for command " + Arrays.asList(cmdAttribs)); - } finally { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(out); - IOUtils.closeQuietly(err); - IOUtils.closeQuietly(inr); - if (proc != null) { - proc.destroy(); - } - } - } - - /** - * Opens the process to the operating system. - * - * @param cmdAttribs the command line parameters - * @return the process - * @throws IOException if an error occurs - */ - Process openProcess(String[] cmdAttribs) throws IOException { - return Runtime.getRuntime().exec(cmdAttribs); - } - -} diff --git a/src/org/apache/commons/io/FileUtils.java b/src/org/apache/commons/io/FileUtils.java deleted file mode 100644 index 254800cd1..000000000 --- a/src/org/apache/commons/io/FileUtils.java +++ /dev/null @@ -1,1890 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.zip.CRC32; -import java.util.zip.CheckedInputStream; -import java.util.zip.Checksum; - -import org.apache.commons.io.filefilter.DirectoryFileFilter; -import org.apache.commons.io.filefilter.FalseFileFilter; -import org.apache.commons.io.filefilter.FileFilterUtils; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.apache.commons.io.filefilter.SuffixFileFilter; -import org.apache.commons.io.filefilter.TrueFileFilter; -import org.apache.commons.io.output.NullOutputStream; - -/** - * General file manipulation utilities. - *

- * Facilities are provided in the following areas: - *

    - *
  • writing to a file - *
  • reading from a file - *
  • make a directory including parent directories - *
  • copying files and directories - *
  • deleting files and directories - *
  • converting to and from a URL - *
  • listing files and directories by filter and extension - *
  • comparing file content - *
  • file last changed date - *
  • calculating a checksum - *
- *

- * Origin of code: Excalibur, Alexandria, Commons-Utils - * - * @author Kevin A. Burton - * @author Scott Sanders - * @author Daniel Rall - * @author Christoph.Reck - * @author Peter Donald - * @author Jeff Turner - * @author Matthew Hawthorne - * @author Jeremias Maerki - * @author Stephen Colebourne - * @author Ian Springer - * @author Chris Eldredge - * @author Jim Harrington - * @author Niall Pemberton - * @author Sandy McArthur - * @version $Id: FileUtils.java 610810 2008-01-10 15:04:49Z niallp $ - */ -public class FileUtils { - - /** - * Instances should NOT be constructed in standard programming. - */ - public FileUtils() { - super(); - } - - /** - * The number of bytes in a kilobyte. - */ - public static final long ONE_KB = 1024; - - /** - * The number of bytes in a megabyte. - */ - public static final long ONE_MB = ONE_KB * ONE_KB; - - /** - * The number of bytes in a gigabyte. - */ - public static final long ONE_GB = ONE_KB * ONE_MB; - - /** - * An empty array of type File. - */ - public static final File[] EMPTY_FILE_ARRAY = new File[0]; - - //----------------------------------------------------------------------- - /** - * Opens a {@link FileInputStream} for the specified file, providing better - * error messages than simply calling new FileInputStream(file). - *

- * At the end of the method either the stream will be successfully opened, - * or an exception will have been thrown. - *

- * An exception is thrown if the file does not exist. - * An exception is thrown if the file object exists but is a directory. - * An exception is thrown if the file exists but cannot be read. - * - * @param file the file to open for input, must not be null - * @return a new {@link FileInputStream} for the specified file - * @throws FileNotFoundException if the file does not exist - * @throws IOException if the file object is a directory - * @throws IOException if the file cannot be read - * @since Commons IO 1.3 - */ - public static FileInputStream openInputStream(File file) throws IOException { - if (file.exists()) { - if (file.isDirectory()) { - throw new IOException("File '" + file + "' exists but is a directory"); - } - if (file.canRead() == false) { - throw new IOException("File '" + file + "' cannot be read"); - } - } else { - throw new FileNotFoundException("File '" + file + "' does not exist"); - } - return new FileInputStream(file); - } - - //----------------------------------------------------------------------- - /** - * Opens a {@link FileOutputStream} for the specified file, checking and - * creating the parent directory if it does not exist. - *

- * At the end of the method either the stream will be successfully opened, - * or an exception will have been thrown. - *

- * The parent directory will be created if it does not exist. - * The file will be created if it does not exist. - * An exception is thrown if the file object exists but is a directory. - * An exception is thrown if the file exists but cannot be written to. - * An exception is thrown if the parent directory cannot be created. - * - * @param file the file to open for output, must not be null - * @return a new {@link FileOutputStream} for the specified file - * @throws IOException if the file object is a directory - * @throws IOException if the file cannot be written to - * @throws IOException if a parent directory needs creating but that fails - * @since Commons IO 1.3 - */ - public static FileOutputStream openOutputStream(File file) throws IOException { - if (file.exists()) { - if (file.isDirectory()) { - throw new IOException("File '" + file + "' exists but is a directory"); - } - if (file.canWrite() == false) { - throw new IOException("File '" + file + "' cannot be written to"); - } - } else { - File parent = file.getParentFile(); - if (parent != null && parent.exists() == false) { - if (parent.mkdirs() == false) { - throw new IOException("File '" + file + "' could not be created"); - } - } - } - return new FileOutputStream(file); - } - - //----------------------------------------------------------------------- - /** - * Returns a human-readable version of the file size, where the input - * represents a specific number of bytes. - * - * @param size the number of bytes - * @return a human-readable display value (includes units) - */ - public static String byteCountToDisplaySize(long size) { - String displaySize; - - if (size / ONE_GB > 0) { - displaySize = String.valueOf(size / ONE_GB) + " GB"; - } else if (size / ONE_MB > 0) { - displaySize = String.valueOf(size / ONE_MB) + " MB"; - } else if (size / ONE_KB > 0) { - displaySize = String.valueOf(size / ONE_KB) + " KB"; - } else { - displaySize = String.valueOf(size) + " bytes"; - } - return displaySize; - } - - //----------------------------------------------------------------------- - /** - * Implements the same behaviour as the "touch" utility on Unix. It creates - * a new file with size 0 or, if the file exists already, it is opened and - * closed without modifying it, but updating the file date and time. - *

- * NOTE: As from v1.3, this method throws an IOException if the last - * modified date of the file cannot be set. Also, as from v1.3 this method - * creates parent directories if they do not exist. - * - * @param file the File to touch - * @throws IOException If an I/O problem occurs - */ - public static void touch(File file) throws IOException { - if (!file.exists()) { - OutputStream out = openOutputStream(file); - IOUtils.closeQuietly(out); - } - boolean success = file.setLastModified(System.currentTimeMillis()); - if (!success) { - throw new IOException("Unable to set the last modification time for " + file); - } - } - - //----------------------------------------------------------------------- - /** - * Converts a Collection containing java.io.File instanced into array - * representation. This is to account for the difference between - * File.listFiles() and FileUtils.listFiles(). - * - * @param files a Collection containing java.io.File instances - * @return an array of java.io.File - */ - public static File[] convertFileCollectionToFileArray(Collection files) { - return (File[]) files.toArray(new File[files.size()]); - } - - //----------------------------------------------------------------------- - /** - * Finds files within a given directory (and optionally its - * subdirectories). All files found are filtered by an IOFileFilter. - * - * @param files the collection of files found. - * @param directory the directory to search in. - * @param filter the filter to apply to files and directories. - */ - private static void innerListFiles(Collection files, File directory, - IOFileFilter filter) { - File[] found = directory.listFiles((FileFilter) filter); - if (found != null) { - for (int i = 0; i < found.length; i++) { - if (found[i].isDirectory()) { - innerListFiles(files, found[i], filter); - } else { - files.add(found[i]); - } - } - } - } - - /** - * Finds files within a given directory (and optionally its - * subdirectories). All files found are filtered by an IOFileFilter. - *

- * If your search should recurse into subdirectories you can pass in - * an IOFileFilter for directories. You don't need to bind a - * DirectoryFileFilter (via logical AND) to this filter. This method does - * that for you. - *

- * An example: If you want to search through all directories called - * "temp" you pass in FileFilterUtils.NameFileFilter("temp") - *

- * Another common usage of this method is find files in a directory - * tree but ignoring the directories generated CVS. You can simply pass - * in FileFilterUtils.makeCVSAware(null). - * - * @param directory the directory to search in - * @param fileFilter filter to apply when finding files. - * @param dirFilter optional filter to apply when finding subdirectories. - * If this parameter is null, subdirectories will not be included in the - * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an collection of java.io.File with the matching files - * @see org.apache.commons.io.filefilter.FileFilterUtils - * @see org.apache.commons.io.filefilter.NameFileFilter - */ - public static Collection listFiles( - File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) { - if (!directory.isDirectory()) { - throw new IllegalArgumentException( - "Parameter 'directory' is not a directory"); - } - if (fileFilter == null) { - throw new NullPointerException("Parameter 'fileFilter' is null"); - } - - //Setup effective file filter - IOFileFilter effFileFilter = FileFilterUtils.andFileFilter(fileFilter, - FileFilterUtils.notFileFilter(DirectoryFileFilter.INSTANCE)); - - //Setup effective directory filter - IOFileFilter effDirFilter; - if (dirFilter == null) { - effDirFilter = FalseFileFilter.INSTANCE; - } else { - effDirFilter = FileFilterUtils.andFileFilter(dirFilter, - DirectoryFileFilter.INSTANCE); - } - - //Find files - Collection files = new java.util.LinkedList(); - innerListFiles(files, directory, - FileFilterUtils.orFileFilter(effFileFilter, effDirFilter)); - return files; - } - - /** - * Allows iteration over the files in given directory (and optionally - * its subdirectories). - *

- * All files found are filtered by an IOFileFilter. This method is - * based on {@link #listFiles(File, IOFileFilter, IOFileFilter)}. - * - * @param directory the directory to search in - * @param fileFilter filter to apply when finding files. - * @param dirFilter optional filter to apply when finding subdirectories. - * If this parameter is null, subdirectories will not be included in the - * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an iterator of java.io.File for the matching files - * @see org.apache.commons.io.filefilter.FileFilterUtils - * @see org.apache.commons.io.filefilter.NameFileFilter - * @since Commons IO 1.2 - */ - public static Iterator iterateFiles( - File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) { - return listFiles(directory, fileFilter, dirFilter).iterator(); - } - - //----------------------------------------------------------------------- - /** - * Converts an array of file extensions to suffixes for use - * with IOFileFilters. - * - * @param extensions an array of extensions. Format: {"java", "xml"} - * @return an array of suffixes. Format: {".java", ".xml"} - */ - private static String[] toSuffixes(String[] extensions) { - String[] suffixes = new String[extensions.length]; - for (int i = 0; i < extensions.length; i++) { - suffixes[i] = "." + extensions[i]; - } - return suffixes; - } - - - /** - * Finds files within a given directory (and optionally its subdirectories) - * which match an array of extensions. - * - * @param directory the directory to search in - * @param extensions an array of extensions, ex. {"java","xml"}. If this - * parameter is null, all files are returned. - * @param recursive if true all subdirectories are searched as well - * @return an collection of java.io.File with the matching files - */ - public static Collection listFiles( - File directory, String[] extensions, boolean recursive) { - IOFileFilter filter; - if (extensions == null) { - filter = TrueFileFilter.INSTANCE; - } else { - String[] suffixes = toSuffixes(extensions); - filter = new SuffixFileFilter(suffixes); - } - return listFiles(directory, filter, - (recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE)); - } - - /** - * Allows iteration over the files in a given directory (and optionally - * its subdirectories) which match an array of extensions. This method - * is based on {@link #listFiles(File, String[], boolean)}. - * - * @param directory the directory to search in - * @param extensions an array of extensions, ex. {"java","xml"}. If this - * parameter is null, all files are returned. - * @param recursive if true all subdirectories are searched as well - * @return an iterator of java.io.File with the matching files - * @since Commons IO 1.2 - */ - public static Iterator iterateFiles( - File directory, String[] extensions, boolean recursive) { - return listFiles(directory, extensions, recursive).iterator(); - } - - //----------------------------------------------------------------------- - /** - * Compares the contents of two files to determine if they are equal or not. - *

- * This method checks to see if the two files are different lengths - * or if they point to the same file, before resorting to byte-by-byte - * comparison of the contents. - *

- * Code origin: Avalon - * - * @param file1 the first file - * @param file2 the second file - * @return true if the content of the files are equal or they both don't - * exist, false otherwise - * @throws IOException in case of an I/O error - */ - public static boolean contentEquals(File file1, File file2) throws IOException { - boolean file1Exists = file1.exists(); - if (file1Exists != file2.exists()) { - return false; - } - - if (!file1Exists) { - // two not existing files are equal - return true; - } - - if (file1.isDirectory() || file2.isDirectory()) { - // don't want to compare directory contents - throw new IOException("Can't compare directories, only files"); - } - - if (file1.length() != file2.length()) { - // lengths differ, cannot be equal - return false; - } - - if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { - // same file - return true; - } - - InputStream input1 = null; - InputStream input2 = null; - try { - input1 = new FileInputStream(file1); - input2 = new FileInputStream(file2); - return IOUtils.contentEquals(input1, input2); - - } finally { - IOUtils.closeQuietly(input1); - IOUtils.closeQuietly(input2); - } - } - - //----------------------------------------------------------------------- - /** - * Convert from a URL to a File. - *

- * From version 1.1 this method will decode the URL. - * Syntax such as file:///my%20docs/file.txt will be - * correctly decoded to /my docs/file.txt. - * - * @param url the file URL to convert, null returns null - * @return the equivalent File object, or null - * if the URL's protocol is not file - * @throws IllegalArgumentException if the file is incorrectly encoded - */ - public static File toFile(URL url) { - if (url == null || !url.getProtocol().equals("file")) { - return null; - } else { - String filename = url.getFile().replace('/', File.separatorChar); - int pos =0; - while ((pos = filename.indexOf('%', pos)) >= 0) { - if (pos + 2 < filename.length()) { - String hexStr = filename.substring(pos + 1, pos + 3); - char ch = (char) Integer.parseInt(hexStr, 16); - filename = filename.substring(0, pos) + ch + filename.substring(pos + 3); - } - } - return new File(filename); - } - } - - /** - * Converts each of an array of URL to a File. - *

- * Returns an array of the same size as the input. - * If the input is null, an empty array is returned. - * If the input contains null, the output array contains null at the same - * index. - *

- * This method will decode the URL. - * Syntax such as file:///my%20docs/file.txt will be - * correctly decoded to /my docs/file.txt. - * - * @param urls the file URLs to convert, null returns empty array - * @return a non-null array of Files matching the input, with a null item - * if there was a null at that index in the input array - * @throws IllegalArgumentException if any file is not a URL file - * @throws IllegalArgumentException if any file is incorrectly encoded - * @since Commons IO 1.1 - */ - public static File[] toFiles(URL[] urls) { - if (urls == null || urls.length == 0) { - return EMPTY_FILE_ARRAY; - } - File[] files = new File[urls.length]; - for (int i = 0; i < urls.length; i++) { - URL url = urls[i]; - if (url != null) { - if (url.getProtocol().equals("file") == false) { - throw new IllegalArgumentException( - "URL could not be converted to a File: " + url); - } - files[i] = toFile(url); - } - } - return files; - } - - /** - * Converts each of an array of File to a URL. - *

- * Returns an array of the same size as the input. - * - * @param files the files to convert - * @return an array of URLs matching the input - * @throws IOException if a file cannot be converted - */ - public static URL[] toURLs(File[] files) throws IOException { - URL[] urls = new URL[files.length]; - - for (int i = 0; i < urls.length; i++) { - urls[i] = files[i].toURL(); - } - - return urls; - } - - //----------------------------------------------------------------------- - /** - * Copies a file to a directory preserving the file date. - *

- * This method copies the contents of the specified source file - * to a file of the same name in the specified destination directory. - * The destination directory is created if it does not exist. - * If the destination file exists, then this method will overwrite it. - * - * @param srcFile an existing file to copy, must not be null - * @param destDir the directory to place the copy in, must not be null - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @see #copyFile(File, File, boolean) - */ - public static void copyFileToDirectory(File srcFile, File destDir) throws IOException { - copyFileToDirectory(srcFile, destDir, true); - } - - /** - * Copies a file to a directory optionally preserving the file date. - *

- * This method copies the contents of the specified source file - * to a file of the same name in the specified destination directory. - * The destination directory is created if it does not exist. - * If the destination file exists, then this method will overwrite it. - * - * @param srcFile an existing file to copy, must not be null - * @param destDir the directory to place the copy in, must not be null - * @param preserveFileDate true if the file date of the copy - * should be the same as the original - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @see #copyFile(File, File, boolean) - * @since Commons IO 1.3 - */ - public static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate) throws IOException { - if (destDir == null) { - throw new NullPointerException("Destination must not be null"); - } - if (destDir.exists() && destDir.isDirectory() == false) { - throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory"); - } - copyFile(srcFile, new File(destDir, srcFile.getName()), preserveFileDate); - } - - /** - * Copies a file to a new location preserving the file date. - *

- * This method copies the contents of the specified source file to the - * specified destination file. The directory holding the destination file is - * created if it does not exist. If the destination file exists, then this - * method will overwrite it. - * - * @param srcFile an existing file to copy, must not be null - * @param destFile the new file, must not be null - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @see #copyFileToDirectory(File, File) - */ - public static void copyFile(File srcFile, File destFile) throws IOException { - copyFile(srcFile, destFile, true); - } - - /** - * Copies a file to a new location. - *

- * This method copies the contents of the specified source file - * to the specified destination file. - * The directory holding the destination file is created if it does not exist. - * If the destination file exists, then this method will overwrite it. - * - * @param srcFile an existing file to copy, must not be null - * @param destFile the new file, must not be null - * @param preserveFileDate true if the file date of the copy - * should be the same as the original - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @see #copyFileToDirectory(File, File, boolean) - */ - public static void copyFile(File srcFile, File destFile, - boolean preserveFileDate) throws IOException { - if (srcFile == null) { - throw new NullPointerException("Source must not be null"); - } - if (destFile == null) { - throw new NullPointerException("Destination must not be null"); - } - if (srcFile.exists() == false) { - throw new FileNotFoundException("Source '" + srcFile + "' does not exist"); - } - if (srcFile.isDirectory()) { - throw new IOException("Source '" + srcFile + "' exists but is a directory"); - } - if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) { - throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same"); - } - if (destFile.getParentFile() != null && destFile.getParentFile().exists() == false) { - if (destFile.getParentFile().mkdirs() == false) { - throw new IOException("Destination '" + destFile + "' directory cannot be created"); - } - } - if (destFile.exists() && destFile.canWrite() == false) { - throw new IOException("Destination '" + destFile + "' exists but is read-only"); - } - doCopyFile(srcFile, destFile, preserveFileDate); - } - - /** - * Internal copy file method. - * - * @param srcFile the validated source file, must not be null - * @param destFile the validated destination file, must not be null - * @param preserveFileDate whether to preserve the file date - * @throws IOException if an error occurs - */ - private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException { - if (destFile.exists() && destFile.isDirectory()) { - throw new IOException("Destination '" + destFile + "' exists but is a directory"); - } - - FileInputStream input = new FileInputStream(srcFile); - try { - FileOutputStream output = new FileOutputStream(destFile); - try { - IOUtils.copy(input, output); - } finally { - IOUtils.closeQuietly(output); - } - } finally { - IOUtils.closeQuietly(input); - } - - if (srcFile.length() != destFile.length()) { - throw new IOException("Failed to copy full contents from '" + - srcFile + "' to '" + destFile + "'"); - } - if (preserveFileDate) { - destFile.setLastModified(srcFile.lastModified()); - } - } - - //----------------------------------------------------------------------- - /** - * Copies a directory to within another directory preserving the file dates. - *

- * This method copies the source directory and all its contents to a - * directory of the same name in the specified destination directory. - *

- * The destination directory is created if it does not exist. - * If the destination directory did exist, then this method merges - * the source with the destination, with the source taking precedence. - * - * @param srcDir an existing directory to copy, must not be null - * @param destDir the directory to place the copy in, must not be null - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @since Commons IO 1.2 - */ - public static void copyDirectoryToDirectory(File srcDir, File destDir) throws IOException { - if (srcDir == null) { - throw new NullPointerException("Source must not be null"); - } - if (srcDir.exists() && srcDir.isDirectory() == false) { - throw new IllegalArgumentException("Source '" + destDir + "' is not a directory"); - } - if (destDir == null) { - throw new NullPointerException("Destination must not be null"); - } - if (destDir.exists() && destDir.isDirectory() == false) { - throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory"); - } - copyDirectory(srcDir, new File(destDir, srcDir.getName()), true); - } - - /** - * Copies a whole directory to a new location preserving the file dates. - *

- * This method copies the specified directory and all its child - * directories and files to the specified destination. - * The destination is the new location and name of the directory. - *

- * The destination directory is created if it does not exist. - * If the destination directory did exist, then this method merges - * the source with the destination, with the source taking precedence. - * - * @param srcDir an existing directory to copy, must not be null - * @param destDir the new directory, must not be null - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @since Commons IO 1.1 - */ - public static void copyDirectory(File srcDir, File destDir) throws IOException { - copyDirectory(srcDir, destDir, true); - } - - /** - * Copies a whole directory to a new location. - *

- * This method copies the contents of the specified source directory - * to within the specified destination directory. - *

- * The destination directory is created if it does not exist. - * If the destination directory did exist, then this method merges - * the source with the destination, with the source taking precedence. - * - * @param srcDir an existing directory to copy, must not be null - * @param destDir the new directory, must not be null - * @param preserveFileDate true if the file date of the copy - * should be the same as the original - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @since Commons IO 1.1 - */ - public static void copyDirectory(File srcDir, File destDir, - boolean preserveFileDate) throws IOException { - copyDirectory(srcDir, destDir, null, preserveFileDate); - } - - /** - * Copies a filtered directory to a new location preserving the file dates. - *

- * This method copies the contents of the specified source directory - * to within the specified destination directory. - *

- * The destination directory is created if it does not exist. - * If the destination directory did exist, then this method merges - * the source with the destination, with the source taking precedence. - * - *

Example: Copy directories only

- *
-     *  // only copy the directory structure
-     *  FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY);
-     *  
- * - *

Example: Copy directories and txt files

- *
-     *  // Create a filter for ".txt" files
-     *  IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
-     *  IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
-     *
-     *  // Create a filter for either directories or ".txt" files
-     *  FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
-     *
-     *  // Copy using the filter
-     *  FileUtils.copyDirectory(srcDir, destDir, filter);
-     *  
- * - * @param srcDir an existing directory to copy, must not be null - * @param destDir the new directory, must not be null - * @param filter the filter to apply, null means copy all directories and files - * should be the same as the original - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @since Commons IO 1.4 - */ - public static void copyDirectory(File srcDir, File destDir, - FileFilter filter) throws IOException { - copyDirectory(srcDir, destDir, filter, true); - } - - /** - * Copies a filtered directory to a new location. - *

- * This method copies the contents of the specified source directory - * to within the specified destination directory. - *

- * The destination directory is created if it does not exist. - * If the destination directory did exist, then this method merges - * the source with the destination, with the source taking precedence. - * - *

Example: Copy directories only

- *
-     *  // only copy the directory structure
-     *  FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
-     *  
- * - *

Example: Copy directories and txt files

- *
-     *  // Create a filter for ".txt" files
-     *  IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
-     *  IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
-     *
-     *  // Create a filter for either directories or ".txt" files
-     *  FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
-     *
-     *  // Copy using the filter
-     *  FileUtils.copyDirectory(srcDir, destDir, filter, false);
-     *  
- * - * @param srcDir an existing directory to copy, must not be null - * @param destDir the new directory, must not be null - * @param filter the filter to apply, null means copy all directories and files - * @param preserveFileDate true if the file date of the copy - * should be the same as the original - * - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs during copying - * @since Commons IO 1.4 - */ - public static void copyDirectory(File srcDir, File destDir, - FileFilter filter, boolean preserveFileDate) throws IOException { - if (srcDir == null) { - throw new NullPointerException("Source must not be null"); - } - if (destDir == null) { - throw new NullPointerException("Destination must not be null"); - } - if (srcDir.exists() == false) { - throw new FileNotFoundException("Source '" + srcDir + "' does not exist"); - } - if (srcDir.isDirectory() == false) { - throw new IOException("Source '" + srcDir + "' exists but is not a directory"); - } - if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) { - throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same"); - } - - // Cater for destination being directory within the source directory (see IO-141) - List exclusionList = null; - if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) { - File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter); - if (srcFiles != null && srcFiles.length > 0) { - exclusionList = new ArrayList(srcFiles.length); - for (int i = 0; i < srcFiles.length; i++) { - File copiedFile = new File(destDir, srcFiles[i].getName()); - exclusionList.add(copiedFile.getCanonicalPath()); - } - } - } - doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList); - } - - /** - * Internal copy directory method. - * - * @param srcDir the validated source directory, must not be null - * @param destDir the validated destination directory, must not be null - * @param filter the filter to apply, null means copy all directories and files - * @param preserveFileDate whether to preserve the file date - * @param exclusionList List of files and directories to exclude from the copy, may be null - * @throws IOException if an error occurs - * @since Commons IO 1.1 - */ - private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter, - boolean preserveFileDate, List exclusionList) throws IOException { - if (destDir.exists()) { - if (destDir.isDirectory() == false) { - throw new IOException("Destination '" + destDir + "' exists but is not a directory"); - } - } else { - if (destDir.mkdirs() == false) { - throw new IOException("Destination '" + destDir + "' directory cannot be created"); - } - if (preserveFileDate) { - destDir.setLastModified(srcDir.lastModified()); - } - } - if (destDir.canWrite() == false) { - throw new IOException("Destination '" + destDir + "' cannot be written to"); - } - // recurse - File[] files = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter); - if (files == null) { // null if security restricted - throw new IOException("Failed to list contents of " + srcDir); - } - for (int i = 0; i < files.length; i++) { - File copiedFile = new File(destDir, files[i].getName()); - if (exclusionList == null || !exclusionList.contains(files[i].getCanonicalPath())) { - if (files[i].isDirectory()) { - doCopyDirectory(files[i], copiedFile, filter, preserveFileDate, exclusionList); - } else { - doCopyFile(files[i], copiedFile, preserveFileDate); - } - } - } - } - - //----------------------------------------------------------------------- - /** - * Copies bytes from the URL source to a file - * destination. The directories up to destination - * will be created if they don't already exist. destination - * will be overwritten if it already exists. - * - * @param source the URL to copy bytes from, must not be null - * @param destination the non-directory File to write bytes to - * (possibly overwriting), must not be null - * @throws IOException if source URL cannot be opened - * @throws IOException if destination is a directory - * @throws IOException if destination cannot be written - * @throws IOException if destination needs creating but can't be - * @throws IOException if an IO error occurs during copying - */ - public static void copyURLToFile(URL source, File destination) throws IOException { - InputStream input = source.openStream(); - try { - FileOutputStream output = openOutputStream(destination); - try { - IOUtils.copy(input, output); - } finally { - IOUtils.closeQuietly(output); - } - } finally { - IOUtils.closeQuietly(input); - } - } - - //----------------------------------------------------------------------- - /** - * Deletes a directory recursively. - * - * @param directory directory to delete - * @throws IOException in case deletion is unsuccessful - */ - public static void deleteDirectory(File directory) throws IOException { - if (!directory.exists()) { - return; - } - - cleanDirectory(directory); - if (!directory.delete()) { - String message = - "Unable to delete directory " + directory + "."; - throw new IOException(message); - } - } - - /** - * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. - *

- * The difference between File.delete() and this method are: - *

    - *
  • A directory to be deleted does not have to be empty.
  • - *
  • No exceptions are thrown when a file or directory cannot be deleted.
  • - *
- * - * @param file file or directory to delete, can be null - * @return true if the file or directory was deleted, otherwise - * false - * - * @since Commons IO 1.4 - */ - public static boolean deleteQuietly(File file) { - if (file == null) { - return false; - } - try { - if (file.isDirectory()) { - cleanDirectory(file); - } - } catch (Exception e) { - } - - try { - return file.delete(); - } catch (Exception e) { - return false; - } - } - - /** - * Cleans a directory without deleting it. - * - * @param directory directory to clean - * @throws IOException in case cleaning is unsuccessful - */ - public static void cleanDirectory(File directory) throws IOException { - if (!directory.exists()) { - String message = directory + " does not exist"; - throw new IllegalArgumentException(message); - } - - if (!directory.isDirectory()) { - String message = directory + " is not a directory"; - throw new IllegalArgumentException(message); - } - - File[] files = directory.listFiles(); - if (files == null) { // null if security restricted - throw new IOException("Failed to list contents of " + directory); - } - - IOException exception = null; - for (int i = 0; i < files.length; i++) { - File file = files[i]; - try { - forceDelete(file); - } catch (IOException ioe) { - exception = ioe; - } - } - - if (null != exception) { - throw exception; - } - } - - //----------------------------------------------------------------------- - /** - * Waits for NFS to propagate a file creation, imposing a timeout. - *

- * This method repeatedly tests {@link File#exists()} until it returns - * true up to the maximum time specified in seconds. - * - * @param file the file to check, must not be null - * @param seconds the maximum time in seconds to wait - * @return true if file exists - * @throws NullPointerException if the file is null - */ - public static boolean waitFor(File file, int seconds) { - int timeout = 0; - int tick = 0; - while (!file.exists()) { - if (tick++ >= 10) { - tick = 0; - if (timeout++ > seconds) { - return false; - } - } - try { - Thread.sleep(100); - } catch (InterruptedException ignore) { - // ignore exception - } catch (Exception ex) { - break; - } - } - return true; - } - - //----------------------------------------------------------------------- - /** - * Reads the contents of a file into a String. - * The file is always closed. - * - * @param file the file to read, must not be null - * @param encoding the encoding to use, null means platform default - * @return the file contents, never null - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - */ - public static String readFileToString(File file, String encoding) throws IOException { - InputStream in = null; - try { - in = openInputStream(file); - return IOUtils.toString(in, encoding); - } finally { - IOUtils.closeQuietly(in); - } - } - - - /** - * Reads the contents of a file into a String using the default encoding for the VM. - * The file is always closed. - * - * @param file the file to read, must not be null - * @return the file contents, never null - * @throws IOException in case of an I/O error - * @since Commons IO 1.3.1 - */ - public static String readFileToString(File file) throws IOException { - return readFileToString(file, null); - } - - /** - * Reads the contents of a file into a byte array. - * The file is always closed. - * - * @param file the file to read, must not be null - * @return the file contents, never null - * @throws IOException in case of an I/O error - * @since Commons IO 1.1 - */ - public static byte[] readFileToByteArray(File file) throws IOException { - InputStream in = null; - try { - in = openInputStream(file); - return IOUtils.toByteArray(in); - } finally { - IOUtils.closeQuietly(in); - } - } - - /** - * Reads the contents of a file line by line to a List of Strings. - * The file is always closed. - * - * @param file the file to read, must not be null - * @param encoding the encoding to use, null means platform default - * @return the list of Strings representing each line in the file, never null - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since Commons IO 1.1 - */ - public static List readLines(File file, String encoding) throws IOException { - InputStream in = null; - try { - in = openInputStream(file); - return IOUtils.readLines(in, encoding); - } finally { - IOUtils.closeQuietly(in); - } - } - - /** - * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM. - * The file is always closed. - * - * @param file the file to read, must not be null - * @return the list of Strings representing each line in the file, never null - * @throws IOException in case of an I/O error - * @since Commons IO 1.3 - */ - public static List readLines(File file) throws IOException { - return readLines(file, null); - } - - /** - * Returns an Iterator for the lines in a File. - *

- * This method opens an InputStream for the file. - * When you have finished with the iterator you should close the stream - * to free internal resources. This can be done by calling the - * {@link LineIterator#close()} or - * {@link LineIterator#closeQuietly(LineIterator)} method. - *

- * The recommended usage pattern is: - *

-     * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
-     * try {
-     *   while (it.hasNext()) {
-     *     String line = it.nextLine();
-     *     /// do something with line
-     *   }
-     * } finally {
-     *   LineIterator.closeQuietly(iterator);
-     * }
-     * 
- *

- * If an exception occurs during the creation of the iterator, the - * underlying stream is closed. - * - * @param file the file to open for input, must not be null - * @param encoding the encoding to use, null means platform default - * @return an Iterator of the lines in the file, never null - * @throws IOException in case of an I/O error (file closed) - * @since Commons IO 1.2 - */ - public static LineIterator lineIterator(File file, String encoding) throws IOException { - InputStream in = null; - try { - in = openInputStream(file); - return IOUtils.lineIterator(in, encoding); - } catch (IOException ex) { - IOUtils.closeQuietly(in); - throw ex; - } catch (RuntimeException ex) { - IOUtils.closeQuietly(in); - throw ex; - } - } - - /** - * Returns an Iterator for the lines in a File using the default encoding for the VM. - * - * @param file the file to open for input, must not be null - * @return an Iterator of the lines in the file, never null - * @throws IOException in case of an I/O error (file closed) - * @since Commons IO 1.3 - * @see #lineIterator(File, String) - */ - public static LineIterator lineIterator(File file) throws IOException { - return lineIterator(file, null); - } - - //----------------------------------------------------------------------- - /** - * Writes a String to a file creating the file if it does not exist. - * - * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - * - * @param file the file to write - * @param data the content to write to the file - * @param encoding the encoding to use, null means platform default - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - */ - public static void writeStringToFile(File file, String data, String encoding) throws IOException { - OutputStream out = null; - try { - out = openOutputStream(file); - IOUtils.write(data, out, encoding); - } finally { - IOUtils.closeQuietly(out); - } - } - - /** - * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. - * - * @param file the file to write - * @param data the content to write to the file - * @throws IOException in case of an I/O error - */ - public static void writeStringToFile(File file, String data) throws IOException { - writeStringToFile(file, data, null); - } - - /** - * Writes a byte array to a file creating the file if it does not exist. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - * - * @param file the file to write to - * @param data the content to write to the file - * @throws IOException in case of an I/O error - * @since Commons IO 1.1 - */ - public static void writeByteArrayToFile(File file, byte[] data) throws IOException { - OutputStream out = null; - try { - out = openOutputStream(file); - out.write(data); - } finally { - IOUtils.closeQuietly(out); - } - } - - /** - * Writes the toString() value of each item in a collection to - * the specified File line by line. - * The specified character encoding and the default line ending will be used. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - * - * @param file the file to write to - * @param encoding the encoding to use, null means platform default - * @param lines the lines to write, null entries produce blank lines - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since Commons IO 1.1 - */ - public static void writeLines(File file, String encoding, Collection lines) throws IOException { - writeLines(file, encoding, lines, null); - } - - /** - * Writes the toString() value of each item in a collection to - * the specified File line by line. - * The default VM encoding and the default line ending will be used. - * - * @param file the file to write to - * @param lines the lines to write, null entries produce blank lines - * @throws IOException in case of an I/O error - * @since Commons IO 1.3 - */ - public static void writeLines(File file, Collection lines) throws IOException { - writeLines(file, null, lines, null); - } - - /** - * Writes the toString() value of each item in a collection to - * the specified File line by line. - * The specified character encoding and the line ending will be used. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - * - * @param file the file to write to - * @param encoding the encoding to use, null means platform default - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since Commons IO 1.1 - */ - public static void writeLines(File file, String encoding, Collection lines, String lineEnding) throws IOException { - OutputStream out = null; - try { - out = openOutputStream(file); - IOUtils.writeLines(lines, lineEnding, out, encoding); - } finally { - IOUtils.closeQuietly(out); - } - } - - /** - * Writes the toString() value of each item in a collection to - * the specified File line by line. - * The default VM encoding and the specified line ending will be used. - * - * @param file the file to write to - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @throws IOException in case of an I/O error - * @since Commons IO 1.3 - */ - public static void writeLines(File file, Collection lines, String lineEnding) throws IOException { - writeLines(file, null, lines, lineEnding); - } - - //----------------------------------------------------------------------- - /** - * Deletes a file. If file is a directory, delete it and all sub-directories. - *

- * The difference between File.delete() and this method are: - *

    - *
  • A directory to be deleted does not have to be empty.
  • - *
  • You get exceptions when a file or directory cannot be deleted. - * (java.io.File methods returns a boolean)
  • - *
- * - * @param file file or directory to delete, must not be null - * @throws NullPointerException if the directory is null - * @throws FileNotFoundException if the file was not found - * @throws IOException in case deletion is unsuccessful - */ - public static void forceDelete(File file) throws IOException { - if (file.isDirectory()) { - deleteDirectory(file); - } else { - boolean filePresent = file.exists(); - if (!file.delete()) { - if (!filePresent){ - throw new FileNotFoundException("File does not exist: " + file); - } - String message = - "Unable to delete file: " + file; - throw new IOException(message); - } - } - } - - /** - * Schedules a file to be deleted when JVM exits. - * If file is directory delete it and all sub-directories. - * - * @param file file or directory to delete, must not be null - * @throws NullPointerException if the file is null - * @throws IOException in case deletion is unsuccessful - */ - public static void forceDeleteOnExit(File file) throws IOException { - if (file.isDirectory()) { - deleteDirectoryOnExit(file); - } else { - file.deleteOnExit(); - } - } - - /** - * Schedules a directory recursively for deletion on JVM exit. - * - * @param directory directory to delete, must not be null - * @throws NullPointerException if the directory is null - * @throws IOException in case deletion is unsuccessful - */ - private static void deleteDirectoryOnExit(File directory) throws IOException { - if (!directory.exists()) { - return; - } - - cleanDirectoryOnExit(directory); - directory.deleteOnExit(); - } - - /** - * Cleans a directory without deleting it. - * - * @param directory directory to clean, must not be null - * @throws NullPointerException if the directory is null - * @throws IOException in case cleaning is unsuccessful - */ - private static void cleanDirectoryOnExit(File directory) throws IOException { - if (!directory.exists()) { - String message = directory + " does not exist"; - throw new IllegalArgumentException(message); - } - - if (!directory.isDirectory()) { - String message = directory + " is not a directory"; - throw new IllegalArgumentException(message); - } - - File[] files = directory.listFiles(); - if (files == null) { // null if security restricted - throw new IOException("Failed to list contents of " + directory); - } - - IOException exception = null; - for (int i = 0; i < files.length; i++) { - File file = files[i]; - try { - forceDeleteOnExit(file); - } catch (IOException ioe) { - exception = ioe; - } - } - - if (null != exception) { - throw exception; - } - } - - /** - * Makes a directory, including any necessary but nonexistent parent - * directories. If there already exists a file with specified name or - * the directory cannot be created then an exception is thrown. - * - * @param directory directory to create, must not be null - * @throws NullPointerException if the directory is null - * @throws IOException if the directory cannot be created - */ - public static void forceMkdir(File directory) throws IOException { - if (directory.exists()) { - if (directory.isFile()) { - String message = - "File " - + directory - + " exists and is " - + "not a directory. Unable to create directory."; - throw new IOException(message); - } - } else { - if (!directory.mkdirs()) { - String message = - "Unable to create directory " + directory; - throw new IOException(message); - } - } - } - - //----------------------------------------------------------------------- - /** - * Counts the size of a directory recursively (sum of the length of all files). - * - * @param directory directory to inspect, must not be null - * @return size of directory in bytes, 0 if directory is security restricted - * @throws NullPointerException if the directory is null - */ - public static long sizeOfDirectory(File directory) { - if (!directory.exists()) { - String message = directory + " does not exist"; - throw new IllegalArgumentException(message); - } - - if (!directory.isDirectory()) { - String message = directory + " is not a directory"; - throw new IllegalArgumentException(message); - } - - long size = 0; - - File[] files = directory.listFiles(); - if (files == null) { // null if security restricted - return 0L; - } - for (int i = 0; i < files.length; i++) { - File file = files[i]; - - if (file.isDirectory()) { - size += sizeOfDirectory(file); - } else { - size += file.length(); - } - } - - return size; - } - - //----------------------------------------------------------------------- - /** - * Tests if the specified File is newer than the reference - * File. - * - * @param file the File of which the modification date must - * be compared, must not be null - * @param reference the File of which the modification date - * is used, must not be null - * @return true if the File exists and has been modified more - * recently than the reference File - * @throws IllegalArgumentException if the file is null - * @throws IllegalArgumentException if the reference file is null or doesn't exist - */ - public static boolean isFileNewer(File file, File reference) { - if (reference == null) { - throw new IllegalArgumentException("No specified reference file"); - } - if (!reference.exists()) { - throw new IllegalArgumentException("The reference file '" - + file + "' doesn't exist"); - } - return isFileNewer(file, reference.lastModified()); - } - - /** - * Tests if the specified File is newer than the specified - * Date. - * - * @param file the File of which the modification date - * must be compared, must not be null - * @param date the date reference, must not be null - * @return true if the File exists and has been modified - * after the given Date. - * @throws IllegalArgumentException if the file is null - * @throws IllegalArgumentException if the date is null - */ - public static boolean isFileNewer(File file, Date date) { - if (date == null) { - throw new IllegalArgumentException("No specified date"); - } - return isFileNewer(file, date.getTime()); - } - - /** - * Tests if the specified File is newer than the specified - * time reference. - * - * @param file the File of which the modification date must - * be compared, must not be null - * @param timeMillis the time reference measured in milliseconds since the - * epoch (00:00:00 GMT, January 1, 1970) - * @return true if the File exists and has been modified after - * the given time reference. - * @throws IllegalArgumentException if the file is null - */ - public static boolean isFileNewer(File file, long timeMillis) { - if (file == null) { - throw new IllegalArgumentException("No specified file"); - } - if (!file.exists()) { - return false; - } - return file.lastModified() > timeMillis; - } - - - //----------------------------------------------------------------------- - /** - * Tests if the specified File is older than the reference - * File. - * - * @param file the File of which the modification date must - * be compared, must not be null - * @param reference the File of which the modification date - * is used, must not be null - * @return true if the File exists and has been modified before - * the reference File - * @throws IllegalArgumentException if the file is null - * @throws IllegalArgumentException if the reference file is null or doesn't exist - */ - public static boolean isFileOlder(File file, File reference) { - if (reference == null) { - throw new IllegalArgumentException("No specified reference file"); - } - if (!reference.exists()) { - throw new IllegalArgumentException("The reference file '" - + file + "' doesn't exist"); - } - return isFileOlder(file, reference.lastModified()); - } - - /** - * Tests if the specified File is older than the specified - * Date. - * - * @param file the File of which the modification date - * must be compared, must not be null - * @param date the date reference, must not be null - * @return true if the File exists and has been modified - * before the given Date. - * @throws IllegalArgumentException if the file is null - * @throws IllegalArgumentException if the date is null - */ - public static boolean isFileOlder(File file, Date date) { - if (date == null) { - throw new IllegalArgumentException("No specified date"); - } - return isFileOlder(file, date.getTime()); - } - - /** - * Tests if the specified File is older than the specified - * time reference. - * - * @param file the File of which the modification date must - * be compared, must not be null - * @param timeMillis the time reference measured in milliseconds since the - * epoch (00:00:00 GMT, January 1, 1970) - * @return true if the File exists and has been modified before - * the given time reference. - * @throws IllegalArgumentException if the file is null - */ - public static boolean isFileOlder(File file, long timeMillis) { - if (file == null) { - throw new IllegalArgumentException("No specified file"); - } - if (!file.exists()) { - return false; - } - return file.lastModified() < timeMillis; - } - - //----------------------------------------------------------------------- - /** - * Computes the checksum of a file using the CRC32 checksum routine. - * The value of the checksum is returned. - * - * @param file the file to checksum, must not be null - * @return the checksum value - * @throws NullPointerException if the file or checksum is null - * @throws IllegalArgumentException if the file is a directory - * @throws IOException if an IO error occurs reading the file - * @since Commons IO 1.3 - */ - public static long checksumCRC32(File file) throws IOException { - CRC32 crc = new CRC32(); - checksum(file, crc); - return crc.getValue(); - } - - /** - * Computes the checksum of a file using the specified checksum object. - * Multiple files may be checked using one Checksum instance - * if desired simply by reusing the same checksum object. - * For example: - *
-     *   long csum = FileUtils.checksum(file, new CRC32()).getValue();
-     * 
- * - * @param file the file to checksum, must not be null - * @param checksum the checksum object to be used, must not be null - * @return the checksum specified, updated with the content of the file - * @throws NullPointerException if the file or checksum is null - * @throws IllegalArgumentException if the file is a directory - * @throws IOException if an IO error occurs reading the file - * @since Commons IO 1.3 - */ - public static Checksum checksum(File file, Checksum checksum) throws IOException { - if (file.isDirectory()) { - throw new IllegalArgumentException("Checksums can't be computed on directories"); - } - InputStream in = null; - try { - in = new CheckedInputStream(new FileInputStream(file), checksum); - IOUtils.copy(in, new NullOutputStream()); - } finally { - IOUtils.closeQuietly(in); - } - return checksum; - } - - /** - * Moves a directory. - *

- * When the destination directory is on another file system, do a "copy and delete". - * - * @param srcDir the directory to be moved - * @param destDir the destination directory - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs moving the file - * @since Commons IO 1.4 - */ - public static void moveDirectory(File srcDir, File destDir) throws IOException { - if (srcDir == null) { - throw new NullPointerException("Source must not be null"); - } - if (destDir == null) { - throw new NullPointerException("Destination must not be null"); - } - if (!srcDir.exists()) { - throw new FileNotFoundException("Source '" + srcDir + "' does not exist"); - } - if (!srcDir.isDirectory()) { - throw new IOException("Source '" + srcDir + "' is not a directory"); - } - if (destDir.exists()) { - throw new IOException("Destination '" + destDir + "' already exists"); - } - boolean rename = srcDir.renameTo(destDir); - if (!rename) { - copyDirectory( srcDir, destDir ); - deleteDirectory( srcDir ); - if (srcDir.exists()) { - throw new IOException("Failed to delete original directory '" + srcDir + - "' after copy to '" + destDir + "'"); - } - } - } - - /** - * Moves a directory to another directory. - * - * @param src the file to be moved - * @param destDir the destination file - * @param createDestDir If true create the destination directory, - * otherwise if false throw an IOException - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs moving the file - * @since Commons IO 1.4 - */ - public static void moveDirectoryToDirectory(File src, File destDir, boolean createDestDir) throws IOException { - if (src == null) { - throw new NullPointerException("Source must not be null"); - } - if (destDir == null) { - throw new NullPointerException("Destination directory must not be null"); - } - if (!destDir.exists() && createDestDir) { - destDir.mkdirs(); - } - if (!destDir.exists()) { - throw new FileNotFoundException("Destination directory '" + destDir + - "' does not exist [createDestDir=" + createDestDir +"]"); - } - if (!destDir.isDirectory()) { - throw new IOException("Destination '" + destDir + "' is not a directory"); - } - moveDirectory(src, new File(destDir, src.getName())); - - } - - /** - * Moves a file. - *

- * When the destination file is on another file system, do a "copy and delete". - * - * @param srcFile the file to be moved - * @param destFile the destination file - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs moving the file - * @since Commons IO 1.4 - */ - public static void moveFile(File srcFile, File destFile) throws IOException { - if (srcFile == null) { - throw new NullPointerException("Source must not be null"); - } - if (destFile == null) { - throw new NullPointerException("Destination must not be null"); - } - if (!srcFile.exists()) { - throw new FileNotFoundException("Source '" + srcFile + "' does not exist"); - } - if (srcFile.isDirectory()) { - throw new IOException("Source '" + srcFile + "' is a directory"); - } - if (destFile.exists()) { - throw new IOException("Destination '" + destFile + "' already exists"); - } - if (destFile.isDirectory()) { - throw new IOException("Destination '" + destFile + "' is a directory"); - } - boolean rename = srcFile.renameTo(destFile); - if (!rename) { - copyFile( srcFile, destFile ); - if (!srcFile.delete()) { - FileUtils.deleteQuietly(destFile); - throw new IOException("Failed to delete original file '" + srcFile + - "' after copy to '" + destFile + "'"); - } - } - } - - /** - * Moves a file to a directory. - * - * @param srcFile the file to be moved - * @param destDir the destination file - * @param createDestDir If true create the destination directory, - * otherwise if false throw an IOException - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs moving the file - * @since Commons IO 1.4 - */ - public static void moveFileToDirectory(File srcFile, File destDir, boolean createDestDir) throws IOException { - if (srcFile == null) { - throw new NullPointerException("Source must not be null"); - } - if (destDir == null) { - throw new NullPointerException("Destination directory must not be null"); - } - if (!destDir.exists() && createDestDir) { - destDir.mkdirs(); - } - if (!destDir.exists()) { - throw new FileNotFoundException("Destination directory '" + destDir + - "' does not exist [createDestDir=" + createDestDir +"]"); - } - if (!destDir.isDirectory()) { - throw new IOException("Destination '" + destDir + "' is not a directory"); - } - moveFile(srcFile, new File(destDir, srcFile.getName())); - } - - /** - * Moves a file or directory to the destination directory. - *

- * When the destination is on another file system, do a "copy and delete". - * - * @param src the file or directory to be moved - * @param destDir the destination directory - * @param createDestDir If true create the destination directory, - * otherwise if false throw an IOException - * @throws NullPointerException if source or destination is null - * @throws IOException if source or destination is invalid - * @throws IOException if an IO error occurs moving the file - * @since Commons IO 1.4 - */ - public static void moveToDirectory(File src, File destDir, boolean createDestDir) throws IOException { - if (src == null) { - throw new NullPointerException("Source must not be null"); - } - if (destDir == null) { - throw new NullPointerException("Destination must not be null"); - } - if (!src.exists()) { - throw new FileNotFoundException("Source '" + src + "' does not exist"); - } - if (src.isDirectory()) { - moveDirectoryToDirectory(src, destDir, createDestDir); - } else { - moveFileToDirectory(src, destDir, createDestDir); - } - } - -} diff --git a/src/org/apache/commons/io/FilenameUtils.java b/src/org/apache/commons/io/FilenameUtils.java deleted file mode 100644 index 8e170b147..000000000 --- a/src/org/apache/commons/io/FilenameUtils.java +++ /dev/null @@ -1,1260 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.Stack; - -/** - * General filename and filepath manipulation utilities. - *

- * When dealing with filenames you can hit problems when moving from a Windows - * based development machine to a Unix based production machine. - * This class aims to help avoid those problems. - *

- * NOTE: You may be able to avoid using this class entirely simply by - * using JDK {@link java.io.File File} objects and the two argument constructor - * {@link java.io.File#File(java.io.File, java.lang.String) File(File,String)}. - *

- * Most methods on this class are designed to work the same on both Unix and Windows. - * Those that don't include 'System', 'Unix' or 'Windows' in their name. - *

- * Most methods recognise both separators (forward and back), and both - * sets of prefixes. See the javadoc of each method for details. - *

- * This class defines six components within a filename - * (example C:\dev\project\file.txt): - *

    - *
  • the prefix - C:\
  • - *
  • the path - dev\project\
  • - *
  • the full path - C:\dev\project\
  • - *
  • the name - file.txt
  • - *
  • the base name - file
  • - *
  • the extension - txt
  • - *
- * Note that this class works best if directory filenames end with a separator. - * If you omit the last separator, it is impossible to determine if the filename - * corresponds to a file or a directory. As a result, we have chosen to say - * it corresponds to a file. - *

- * This class only supports Unix and Windows style names. - * Prefixes are matched as follows: - *

- * Windows:
- * a\b\c.txt           --> ""          --> relative
- * \a\b\c.txt          --> "\"         --> current drive absolute
- * C:a\b\c.txt         --> "C:"        --> drive relative
- * C:\a\b\c.txt        --> "C:\"       --> absolute
- * \\server\a\b\c.txt  --> "\\server\" --> UNC
- *
- * Unix:
- * a/b/c.txt           --> ""          --> relative
- * /a/b/c.txt          --> "/"         --> absolute
- * ~/a/b/c.txt         --> "~/"        --> current user
- * ~                   --> "~/"        --> current user (slash added)
- * ~user/a/b/c.txt     --> "~user/"    --> named user
- * ~user               --> "~user/"    --> named user (slash added)
- * 
- * Both prefix styles are matched always, irrespective of the machine that you are - * currently running on. - *

- * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. - * - * @author Kevin A. Burton - * @author Scott Sanders - * @author Daniel Rall - * @author Christoph.Reck - * @author Peter Donald - * @author Jeff Turner - * @author Matthew Hawthorne - * @author Martin Cooper - * @author Jeremias Maerki - * @author Stephen Colebourne - * @version $Id: FilenameUtils.java 609870 2008-01-08 04:46:26Z niallp $ - * @since Commons IO 1.1 - */ -public class FilenameUtils { - - /** - * The extension separator character. - * @since Commons IO 1.4 - */ - public static final char EXTENSION_SEPARATOR = '.'; - - /** - * The extension separator String. - * @since Commons IO 1.4 - */ - public static final String EXTENSION_SEPARATOR_STR = (new Character(EXTENSION_SEPARATOR)).toString(); - - /** - * The Unix separator character. - */ - private static final char UNIX_SEPARATOR = '/'; - - /** - * The Windows separator character. - */ - private static final char WINDOWS_SEPARATOR = '\\'; - - /** - * The system separator character. - */ - private static final char SYSTEM_SEPARATOR = File.separatorChar; - - /** - * The separator character that is the opposite of the system separator. - */ - private static final char OTHER_SEPARATOR; - static { - if (isSystemWindows()) { - OTHER_SEPARATOR = UNIX_SEPARATOR; - } else { - OTHER_SEPARATOR = WINDOWS_SEPARATOR; - } - } - - /** - * Instances should NOT be constructed in standard programming. - */ - public FilenameUtils() { - super(); - } - - //----------------------------------------------------------------------- - /** - * Determines if Windows file system is in use. - * - * @return true if the system is Windows - */ - static boolean isSystemWindows() { - return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR; - } - - //----------------------------------------------------------------------- - /** - * Checks if the character is a separator. - * - * @param ch the character to check - * @return true if it is a separator character - */ - private static boolean isSeparator(char ch) { - return (ch == UNIX_SEPARATOR) || (ch == WINDOWS_SEPARATOR); - } - - //----------------------------------------------------------------------- - /** - * Normalizes a path, removing double and single dot path steps. - *

- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format of the system. - *

- * A trailing slash will be retained. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, null - * is returned. - *

- * The output will be the same on both Unix and Windows except - * for the separator character. - *

-     * /foo//               -->   /foo/
-     * /foo/./              -->   /foo/
-     * /foo/../bar          -->   /bar
-     * /foo/../bar/         -->   /bar/
-     * /foo/../bar/../baz   -->   /baz
-     * //foo//./bar         -->   /foo/bar
-     * /../                 -->   null
-     * ../foo               -->   null
-     * foo/bar/..           -->   foo/
-     * foo/../../bar        -->   null
-     * foo/../bar           -->   bar
-     * //server/foo/../bar  -->   //server/bar
-     * //server/../bar      -->   null
-     * C:\foo\..\bar        -->   C:\bar
-     * C:\..\bar            -->   null
-     * ~/foo/../bar/        -->   ~/bar/
-     * ~/../bar             -->   null
-     * 
- * (Note the file separator returned will be correct for Windows/Unix) - * - * @param filename the filename to normalize, null returns null - * @return the normalized filename, or null if invalid - */ - public static String normalize(String filename) { - return doNormalize(filename, true); - } - - //----------------------------------------------------------------------- - /** - * Normalizes a path, removing double and single dot path steps, - * and removing any final directory separator. - *

- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format of the system. - *

- * A trailing slash will be removed. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, null - * is returned. - *

- * The output will be the same on both Unix and Windows except - * for the separator character. - *

-     * /foo//               -->   /foo
-     * /foo/./              -->   /foo
-     * /foo/../bar          -->   /bar
-     * /foo/../bar/         -->   /bar
-     * /foo/../bar/../baz   -->   /baz
-     * //foo//./bar         -->   /foo/bar
-     * /../                 -->   null
-     * ../foo               -->   null
-     * foo/bar/..           -->   foo
-     * foo/../../bar        -->   null
-     * foo/../bar           -->   bar
-     * //server/foo/../bar  -->   //server/bar
-     * //server/../bar      -->   null
-     * C:\foo\..\bar        -->   C:\bar
-     * C:\..\bar            -->   null
-     * ~/foo/../bar/        -->   ~/bar
-     * ~/../bar             -->   null
-     * 
- * (Note the file separator returned will be correct for Windows/Unix) - * - * @param filename the filename to normalize, null returns null - * @return the normalized filename, or null if invalid - */ - public static String normalizeNoEndSeparator(String filename) { - return doNormalize(filename, false); - } - - /** - * Internal method to perform the normalization. - * - * @param filename the filename - * @param keepSeparator true to keep the final separator - * @return the normalized filename - */ - private static String doNormalize(String filename, boolean keepSeparator) { - if (filename == null) { - return null; - } - int size = filename.length(); - if (size == 0) { - return filename; - } - int prefix = getPrefixLength(filename); - if (prefix < 0) { - return null; - } - - char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy - filename.getChars(0, filename.length(), array, 0); - - // fix separators throughout - for (int i = 0; i < array.length; i++) { - if (array[i] == OTHER_SEPARATOR) { - array[i] = SYSTEM_SEPARATOR; - } - } - - // add extra separator on the end to simplify code below - boolean lastIsDirectory = true; - if (array[size - 1] != SYSTEM_SEPARATOR) { - array[size++] = SYSTEM_SEPARATOR; - lastIsDirectory = false; - } - - // adjoining slashes - for (int i = prefix + 1; i < size; i++) { - if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == SYSTEM_SEPARATOR) { - System.arraycopy(array, i, array, i - 1, size - i); - size--; - i--; - } - } - - // dot slash - for (int i = prefix + 1; i < size; i++) { - if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' && - (i == prefix + 1 || array[i - 2] == SYSTEM_SEPARATOR)) { - if (i == size - 1) { - lastIsDirectory = true; - } - System.arraycopy(array, i + 1, array, i - 1, size - i); - size -=2; - i--; - } - } - - // double dot slash - outer: - for (int i = prefix + 2; i < size; i++) { - if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' && array[i - 2] == '.' && - (i == prefix + 2 || array[i - 3] == SYSTEM_SEPARATOR)) { - if (i == prefix + 2) { - return null; - } - if (i == size - 1) { - lastIsDirectory = true; - } - int j; - for (j = i - 4 ; j >= prefix; j--) { - if (array[j] == SYSTEM_SEPARATOR) { - // remove b/../ from a/b/../c - System.arraycopy(array, i + 1, array, j + 1, size - i); - size -= (i - j); - i = j + 1; - continue outer; - } - } - // remove a/../ from a/../c - System.arraycopy(array, i + 1, array, prefix, size - i); - size -= (i + 1 - prefix); - i = prefix + 1; - } - } - - if (size <= 0) { // should never be less than 0 - return ""; - } - if (size <= prefix) { // should never be less than prefix - return new String(array, 0, size); - } - if (lastIsDirectory && keepSeparator) { - return new String(array, 0, size); // keep trailing separator - } - return new String(array, 0, size - 1); // lose trailing separator - } - - //----------------------------------------------------------------------- - /** - * Concatenates a filename to a base path using normal command line style rules. - *

- * The effect is equivalent to resultant directory after changing - * directory to the first argument, followed by changing directory to - * the second argument. - *

- * The first argument is the base path, the second is the path to concatenate. - * The returned path is always normalized via {@link #normalize(String)}, - * thus .. is handled. - *

- * If pathToAdd is absolute (has an absolute prefix), then - * it will be normalized and returned. - * Otherwise, the paths will be joined, normalized and returned. - *

- * The output will be the same on both Unix and Windows except - * for the separator character. - *

-     * /foo/ + bar          -->   /foo/bar
-     * /foo + bar           -->   /foo/bar
-     * /foo + /bar          -->   /bar
-     * /foo + C:/bar        -->   C:/bar
-     * /foo + C:bar         -->   C:bar (*)
-     * /foo/a/ + ../bar     -->   foo/bar
-     * /foo/ + ../../bar    -->   null
-     * /foo/ + /bar         -->   /bar
-     * /foo/.. + /bar       -->   /bar
-     * /foo + bar/c.txt     -->   /foo/bar/c.txt
-     * /foo/c.txt + bar     -->   /foo/c.txt/bar (!)
-     * 
- * (*) Note that the Windows relative drive prefix is unreliable when - * used with this method. - * (!) Note that the first parameter must be a path. If it ends with a name, then - * the name will be built into the concatenated path. If this might be a problem, - * use {@link #getFullPath(String)} on the base path argument. - * - * @param basePath the base path to attach to, always treated as a path - * @param fullFilenameToAdd the filename (or path) to attach to the base - * @return the concatenated path, or null if invalid - */ - public static String concat(String basePath, String fullFilenameToAdd) { - int prefix = getPrefixLength(fullFilenameToAdd); - if (prefix < 0) { - return null; - } - if (prefix > 0) { - return normalize(fullFilenameToAdd); - } - if (basePath == null) { - return null; - } - int len = basePath.length(); - if (len == 0) { - return normalize(fullFilenameToAdd); - } - char ch = basePath.charAt(len - 1); - if (isSeparator(ch)) { - return normalize(basePath + fullFilenameToAdd); - } else { - return normalize(basePath + '/' + fullFilenameToAdd); - } - } - - //----------------------------------------------------------------------- - /** - * Converts all separators to the Unix separator of forward slash. - * - * @param path the path to be changed, null ignored - * @return the updated path - */ - public static String separatorsToUnix(String path) { - if (path == null || path.indexOf(WINDOWS_SEPARATOR) == -1) { - return path; - } - return path.replace(WINDOWS_SEPARATOR, UNIX_SEPARATOR); - } - - /** - * Converts all separators to the Windows separator of backslash. - * - * @param path the path to be changed, null ignored - * @return the updated path - */ - public static String separatorsToWindows(String path) { - if (path == null || path.indexOf(UNIX_SEPARATOR) == -1) { - return path; - } - return path.replace(UNIX_SEPARATOR, WINDOWS_SEPARATOR); - } - - /** - * Converts all separators to the system separator. - * - * @param path the path to be changed, null ignored - * @return the updated path - */ - public static String separatorsToSystem(String path) { - if (path == null) { - return null; - } - if (isSystemWindows()) { - return separatorsToWindows(path); - } else { - return separatorsToUnix(path); - } - } - - //----------------------------------------------------------------------- - /** - * Returns the length of the filename prefix, such as C:/ or ~/. - *

- * This method will handle a file in either Unix or Windows format. - *

- * The prefix length includes the first slash in the full filename - * if applicable. Thus, it is possible that the length returned is greater - * than the length of the input string. - *

-     * Windows:
-     * a\b\c.txt           --> ""          --> relative
-     * \a\b\c.txt          --> "\"         --> current drive absolute
-     * C:a\b\c.txt         --> "C:"        --> drive relative
-     * C:\a\b\c.txt        --> "C:\"       --> absolute
-     * \\server\a\b\c.txt  --> "\\server\" --> UNC
-     *
-     * Unix:
-     * a/b/c.txt           --> ""          --> relative
-     * /a/b/c.txt          --> "/"         --> absolute
-     * ~/a/b/c.txt         --> "~/"        --> current user
-     * ~                   --> "~/"        --> current user (slash added)
-     * ~user/a/b/c.txt     --> "~user/"    --> named user
-     * ~user               --> "~user/"    --> named user (slash added)
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * ie. both Unix and Windows prefixes are matched regardless. - * - * @param filename the filename to find the prefix in, null returns -1 - * @return the length of the prefix, -1 if invalid or null - */ - public static int getPrefixLength(String filename) { - if (filename == null) { - return -1; - } - int len = filename.length(); - if (len == 0) { - return 0; - } - char ch0 = filename.charAt(0); - if (ch0 == ':') { - return -1; - } - if (len == 1) { - if (ch0 == '~') { - return 2; // return a length greater than the input - } - return (isSeparator(ch0) ? 1 : 0); - } else { - if (ch0 == '~') { - int posUnix = filename.indexOf(UNIX_SEPARATOR, 1); - int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1); - if (posUnix == -1 && posWin == -1) { - return len + 1; // return a length greater than the input - } - posUnix = (posUnix == -1 ? posWin : posUnix); - posWin = (posWin == -1 ? posUnix : posWin); - return Math.min(posUnix, posWin) + 1; - } - char ch1 = filename.charAt(1); - if (ch1 == ':') { - ch0 = Character.toUpperCase(ch0); - if (ch0 >= 'A' && ch0 <= 'Z') { - if (len == 2 || isSeparator(filename.charAt(2)) == false) { - return 2; - } - return 3; - } - return -1; - - } else if (isSeparator(ch0) && isSeparator(ch1)) { - int posUnix = filename.indexOf(UNIX_SEPARATOR, 2); - int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2); - if ((posUnix == -1 && posWin == -1) || posUnix == 2 || posWin == 2) { - return -1; - } - posUnix = (posUnix == -1 ? posWin : posUnix); - posWin = (posWin == -1 ? posUnix : posWin); - return Math.min(posUnix, posWin) + 1; - } else { - return (isSeparator(ch0) ? 1 : 0); - } - } - } - - /** - * Returns the index of the last directory separator character. - *

- * This method will handle a file in either Unix or Windows format. - * The position of the last forward or backslash is returned. - *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to find the last path separator in, null returns -1 - * @return the index of the last separator character, or -1 if there - * is no such character - */ - public static int indexOfLastSeparator(String filename) { - if (filename == null) { - return -1; - } - int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR); - int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR); - return Math.max(lastUnixPos, lastWindowsPos); - } - - /** - * Returns the index of the last extension separator character, which is a dot. - *

- * This method also checks that there is no directory separator after the last dot. - * To do this it uses {@link #indexOfLastSeparator(String)} which will - * handle a file in either Unix or Windows format. - *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to find the last path separator in, null returns -1 - * @return the index of the last separator character, or -1 if there - * is no such character - */ - public static int indexOfExtension(String filename) { - if (filename == null) { - return -1; - } - int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR); - int lastSeparator = indexOfLastSeparator(filename); - return (lastSeparator > extensionPos ? -1 : extensionPos); - } - - //----------------------------------------------------------------------- - /** - * Gets the prefix from a full filename, such as C:/ - * or ~/. - *

- * This method will handle a file in either Unix or Windows format. - * The prefix includes the first slash in the full filename where applicable. - *

-     * Windows:
-     * a\b\c.txt           --> ""          --> relative
-     * \a\b\c.txt          --> "\"         --> current drive absolute
-     * C:a\b\c.txt         --> "C:"        --> drive relative
-     * C:\a\b\c.txt        --> "C:\"       --> absolute
-     * \\server\a\b\c.txt  --> "\\server\" --> UNC
-     *
-     * Unix:
-     * a/b/c.txt           --> ""          --> relative
-     * /a/b/c.txt          --> "/"         --> absolute
-     * ~/a/b/c.txt         --> "~/"        --> current user
-     * ~                   --> "~/"        --> current user (slash added)
-     * ~user/a/b/c.txt     --> "~user/"    --> named user
-     * ~user               --> "~user/"    --> named user (slash added)
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * ie. both Unix and Windows prefixes are matched regardless. - * - * @param filename the filename to query, null returns null - * @return the prefix of the file, null if invalid - */ - public static String getPrefix(String filename) { - if (filename == null) { - return null; - } - int len = getPrefixLength(filename); - if (len < 0) { - return null; - } - if (len > filename.length()) { - return filename + UNIX_SEPARATOR; // we know this only happens for unix - } - return filename.substring(0, len); - } - - /** - * Gets the path from a full filename, which excludes the prefix. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before and - * including the last forward or backslash. - *

-     * C:\a\b\c.txt --> a\b\
-     * ~/a/b/c.txt  --> a/b/
-     * a.txt        --> ""
-     * a/b/c        --> a/b/
-     * a/b/c/       --> a/b/c/
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - *

- * This method drops the prefix from the result. - * See {@link #getFullPath(String)} for the method that retains the prefix. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getPath(String filename) { - return doGetPath(filename, 1); - } - - /** - * Gets the path from a full filename, which excludes the prefix, and - * also excluding the final directory separator. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before the - * last forward or backslash. - *

-     * C:\a\b\c.txt --> a\b
-     * ~/a/b/c.txt  --> a/b
-     * a.txt        --> ""
-     * a/b/c        --> a/b
-     * a/b/c/       --> a/b/c
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - *

- * This method drops the prefix from the result. - * See {@link #getFullPathNoEndSeparator(String)} for the method that retains the prefix. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getPathNoEndSeparator(String filename) { - return doGetPath(filename, 0); - } - - /** - * Does the work of getting the path. - * - * @param filename the filename - * @param separatorAdd 0 to omit the end separator, 1 to return it - * @return the path - */ - private static String doGetPath(String filename, int separatorAdd) { - if (filename == null) { - return null; - } - int prefix = getPrefixLength(filename); - if (prefix < 0) { - return null; - } - int index = indexOfLastSeparator(filename); - if (prefix >= filename.length() || index < 0) { - return ""; - } - return filename.substring(prefix, index + separatorAdd); - } - - /** - * Gets the full path from a full filename, which is the prefix + path. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before and - * including the last forward or backslash. - *

-     * C:\a\b\c.txt --> C:\a\b\
-     * ~/a/b/c.txt  --> ~/a/b/
-     * a.txt        --> ""
-     * a/b/c        --> a/b/
-     * a/b/c/       --> a/b/c/
-     * C:           --> C:
-     * C:\          --> C:\
-     * ~            --> ~/
-     * ~/           --> ~/
-     * ~user        --> ~user/
-     * ~user/       --> ~user/
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getFullPath(String filename) { - return doGetFullPath(filename, true); - } - - /** - * Gets the full path from a full filename, which is the prefix + path, - * and also excluding the final directory separator. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before the - * last forward or backslash. - *

-     * C:\a\b\c.txt --> C:\a\b
-     * ~/a/b/c.txt  --> ~/a/b
-     * a.txt        --> ""
-     * a/b/c        --> a/b
-     * a/b/c/       --> a/b/c
-     * C:           --> C:
-     * C:\          --> C:\
-     * ~            --> ~
-     * ~/           --> ~
-     * ~user        --> ~user
-     * ~user/       --> ~user
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getFullPathNoEndSeparator(String filename) { - return doGetFullPath(filename, false); - } - - /** - * Does the work of getting the path. - * - * @param filename the filename - * @param includeSeparator true to include the end separator - * @return the path - */ - private static String doGetFullPath(String filename, boolean includeSeparator) { - if (filename == null) { - return null; - } - int prefix = getPrefixLength(filename); - if (prefix < 0) { - return null; - } - if (prefix >= filename.length()) { - if (includeSeparator) { - return getPrefix(filename); // add end slash if necessary - } else { - return filename; - } - } - int index = indexOfLastSeparator(filename); - if (index < 0) { - return filename.substring(0, prefix); - } - int end = index + (includeSeparator ? 1 : 0); - return filename.substring(0, end); - } - - /** - * Gets the name minus the path from a full filename. - *

- * This method will handle a file in either Unix or Windows format. - * The text after the last forward or backslash is returned. - *

-     * a/b/c.txt --> c.txt
-     * a.txt     --> a.txt
-     * a/b/c     --> c
-     * a/b/c/    --> ""
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the name of the file without the path, or an empty string if none exists - */ - public static String getName(String filename) { - if (filename == null) { - return null; - } - int index = indexOfLastSeparator(filename); - return filename.substring(index + 1); - } - - /** - * Gets the base name, minus the full path and extension, from a full filename. - *

- * This method will handle a file in either Unix or Windows format. - * The text after the last forward or backslash and before the last dot is returned. - *

-     * a/b/c.txt --> c
-     * a.txt     --> a
-     * a/b/c     --> c
-     * a/b/c/    --> ""
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the name of the file without the path, or an empty string if none exists - */ - public static String getBaseName(String filename) { - return removeExtension(getName(filename)); - } - - /** - * Gets the extension of a filename. - *

- * This method returns the textual part of the filename after the last dot. - * There must be no directory separator after the dot. - *

-     * foo.txt      --> "txt"
-     * a/b/c.jpg    --> "jpg"
-     * a/b.txt/c    --> ""
-     * a/b/c        --> ""
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to retrieve the extension of. - * @return the extension of the file or an empty string if none exists. - */ - public static String getExtension(String filename) { - if (filename == null) { - return null; - } - int index = indexOfExtension(filename); - if (index == -1) { - return ""; - } else { - return filename.substring(index + 1); - } - } - - //----------------------------------------------------------------------- - /** - * Removes the extension from a filename. - *

- * This method returns the textual part of the filename before the last dot. - * There must be no directory separator after the dot. - *

-     * foo.txt    --> foo
-     * a\b\c.jpg  --> a\b\c
-     * a\b\c      --> a\b\c
-     * a.b\c      --> a.b\c
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the filename minus the extension - */ - public static String removeExtension(String filename) { - if (filename == null) { - return null; - } - int index = indexOfExtension(filename); - if (index == -1) { - return filename; - } else { - return filename.substring(0, index); - } - } - - //----------------------------------------------------------------------- - /** - * Checks whether two filenames are equal exactly. - *

- * No processing is performed on the filenames other than comparison, - * thus this is merely a null-safe case-sensitive equals. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SENSITIVE - */ - public static boolean equals(String filename1, String filename2) { - return equals(filename1, filename2, false, IOCase.SENSITIVE); - } - - /** - * Checks whether two filenames are equal using the case rules of the system. - *

- * No processing is performed on the filenames other than comparison. - * The check is case-sensitive on Unix and case-insensitive on Windows. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SYSTEM - */ - public static boolean equalsOnSystem(String filename1, String filename2) { - return equals(filename1, filename2, false, IOCase.SYSTEM); - } - - //----------------------------------------------------------------------- - /** - * Checks whether two filenames are equal after both have been normalized. - *

- * Both filenames are first passed to {@link #normalize(String)}. - * The check is then performed in a case-sensitive manner. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SENSITIVE - */ - public static boolean equalsNormalized(String filename1, String filename2) { - return equals(filename1, filename2, true, IOCase.SENSITIVE); - } - - /** - * Checks whether two filenames are equal after both have been normalized - * and using the case rules of the system. - *

- * Both filenames are first passed to {@link #normalize(String)}. - * The check is then performed case-sensitive on Unix and - * case-insensitive on Windows. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SYSTEM - */ - public static boolean equalsNormalizedOnSystem(String filename1, String filename2) { - return equals(filename1, filename2, true, IOCase.SYSTEM); - } - - /** - * Checks whether two filenames are equal, optionally normalizing and providing - * control over the case-sensitivity. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @param normalized whether to normalize the filenames - * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive - * @return true if the filenames are equal, null equals null - * @since Commons IO 1.3 - */ - public static boolean equals( - String filename1, String filename2, - boolean normalized, IOCase caseSensitivity) { - - if (filename1 == null || filename2 == null) { - return filename1 == filename2; - } - if (normalized) { - filename1 = normalize(filename1); - filename2 = normalize(filename2); - if (filename1 == null || filename2 == null) { - throw new NullPointerException( - "Error normalizing one or both of the file names"); - } - } - if (caseSensitivity == null) { - caseSensitivity = IOCase.SENSITIVE; - } - return caseSensitivity.checkEquals(filename1, filename2); - } - - //----------------------------------------------------------------------- - /** - * Checks whether the extension of the filename is that specified. - *

- * This method obtains the extension as the textual part of the filename - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param filename the filename to query, null returns false - * @param extension the extension to check for, null or empty checks for no extension - * @return true if the filename has the specified extension - */ - public static boolean isExtension(String filename, String extension) { - if (filename == null) { - return false; - } - if (extension == null || extension.length() == 0) { - return (indexOfExtension(filename) == -1); - } - String fileExt = getExtension(filename); - return fileExt.equals(extension); - } - - /** - * Checks whether the extension of the filename is one of those specified. - *

- * This method obtains the extension as the textual part of the filename - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param filename the filename to query, null returns false - * @param extensions the extensions to check for, null checks for no extension - * @return true if the filename is one of the extensions - */ - public static boolean isExtension(String filename, String[] extensions) { - if (filename == null) { - return false; - } - if (extensions == null || extensions.length == 0) { - return (indexOfExtension(filename) == -1); - } - String fileExt = getExtension(filename); - for (int i = 0; i < extensions.length; i++) { - if (fileExt.equals(extensions[i])) { - return true; - } - } - return false; - } - - /** - * Checks whether the extension of the filename is one of those specified. - *

- * This method obtains the extension as the textual part of the filename - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param filename the filename to query, null returns false - * @param extensions the extensions to check for, null checks for no extension - * @return true if the filename is one of the extensions - */ - public static boolean isExtension(String filename, Collection extensions) { - if (filename == null) { - return false; - } - if (extensions == null || extensions.isEmpty()) { - return (indexOfExtension(filename) == -1); - } - String fileExt = getExtension(filename); - for (Iterator it = extensions.iterator(); it.hasNext();) { - if (fileExt.equals(it.next())) { - return true; - } - } - return false; - } - - //----------------------------------------------------------------------- - /** - * Checks a filename to see if it matches the specified wildcard matcher, - * always testing case-sensitive. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The check is case-sensitive always. - *

-     * wildcardMatch("c.txt", "*.txt")      --> true
-     * wildcardMatch("c.txt", "*.jpg")      --> false
-     * wildcardMatch("a/b/c.txt", "a/b/*")  --> true
-     * wildcardMatch("c.txt", "*.???")      --> true
-     * wildcardMatch("c.txt", "*.????")     --> false
-     * 
- * - * @param filename the filename to match on - * @param wildcardMatcher the wildcard string to match against - * @return true if the filename matches the wilcard string - * @see IOCase#SENSITIVE - */ - public static boolean wildcardMatch(String filename, String wildcardMatcher) { - return wildcardMatch(filename, wildcardMatcher, IOCase.SENSITIVE); - } - - /** - * Checks a filename to see if it matches the specified wildcard matcher - * using the case rules of the system. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The check is case-sensitive on Unix and case-insensitive on Windows. - *

-     * wildcardMatch("c.txt", "*.txt")      --> true
-     * wildcardMatch("c.txt", "*.jpg")      --> false
-     * wildcardMatch("a/b/c.txt", "a/b/*")  --> true
-     * wildcardMatch("c.txt", "*.???")      --> true
-     * wildcardMatch("c.txt", "*.????")     --> false
-     * 
- * - * @param filename the filename to match on - * @param wildcardMatcher the wildcard string to match against - * @return true if the filename matches the wilcard string - * @see IOCase#SYSTEM - */ - public static boolean wildcardMatchOnSystem(String filename, String wildcardMatcher) { - return wildcardMatch(filename, wildcardMatcher, IOCase.SYSTEM); - } - - /** - * Checks a filename to see if it matches the specified wildcard matcher - * allowing control over case-sensitivity. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple wildcard characters. - * - * @param filename the filename to match on - * @param wildcardMatcher the wildcard string to match against - * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive - * @return true if the filename matches the wilcard string - * @since Commons IO 1.3 - */ - public static boolean wildcardMatch(String filename, String wildcardMatcher, IOCase caseSensitivity) { - if (filename == null && wildcardMatcher == null) { - return true; - } - if (filename == null || wildcardMatcher == null) { - return false; - } - if (caseSensitivity == null) { - caseSensitivity = IOCase.SENSITIVE; - } - filename = caseSensitivity.convertCase(filename); - wildcardMatcher = caseSensitivity.convertCase(wildcardMatcher); - String[] wcs = splitOnTokens(wildcardMatcher); - boolean anyChars = false; - int textIdx = 0; - int wcsIdx = 0; - Stack backtrack = new Stack(); - - // loop around a backtrack stack, to handle complex * matching - do { - if (backtrack.size() > 0) { - int[] array = (int[]) backtrack.pop(); - wcsIdx = array[0]; - textIdx = array[1]; - anyChars = true; - } - - // loop whilst tokens and text left to process - while (wcsIdx < wcs.length) { - - if (wcs[wcsIdx].equals("?")) { - // ? so move to next text char - textIdx++; - anyChars = false; - - } else if (wcs[wcsIdx].equals("*")) { - // set any chars status - anyChars = true; - if (wcsIdx == wcs.length - 1) { - textIdx = filename.length(); - } - - } else { - // matching text token - if (anyChars) { - // any chars then try to locate text token - textIdx = filename.indexOf(wcs[wcsIdx], textIdx); - if (textIdx == -1) { - // token not found - break; - } - int repeat = filename.indexOf(wcs[wcsIdx], textIdx + 1); - if (repeat >= 0) { - backtrack.push(new int[] {wcsIdx, repeat}); - } - } else { - // matching from current position - if (!filename.startsWith(wcs[wcsIdx], textIdx)) { - // couldnt match token - break; - } - } - - // matched text token, move text index to end of matched token - textIdx += wcs[wcsIdx].length(); - anyChars = false; - } - - wcsIdx++; - } - - // full match - if (wcsIdx == wcs.length && textIdx == filename.length()) { - return true; - } - - } while (backtrack.size() > 0); - - return false; - } - - /** - * Splits a string into a number of tokens. - * - * @param text the text to split - * @return the tokens, never null - */ - static String[] splitOnTokens(String text) { - // used by wildcardMatch - // package level so a unit test may run on this - - if (text.indexOf("?") == -1 && text.indexOf("*") == -1) { - return new String[] { text }; - } - - char[] array = text.toCharArray(); - ArrayList list = new ArrayList(); - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < array.length; i++) { - if (array[i] == '?' || array[i] == '*') { - if (buffer.length() != 0) { - list.add(buffer.toString()); - buffer.setLength(0); - } - if (array[i] == '?') { - list.add("?"); - } else if (list.size() == 0 || - (i > 0 && list.get(list.size() - 1).equals("*") == false)) { - list.add("*"); - } - } else { - buffer.append(array[i]); - } - } - if (buffer.length() != 0) { - list.add(buffer.toString()); - } - - return (String[]) list.toArray( new String[ list.size() ] ); - } - -} diff --git a/src/org/apache/commons/io/HexDump.java b/src/org/apache/commons/io/HexDump.java deleted file mode 100644 index b0d468d18..000000000 --- a/src/org/apache/commons/io/HexDump.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Dumps data in hexadecimal format. - *

- * Provides a single function to take an array of bytes and display it - * in hexadecimal form. - *

- * Origin of code: POI. - * - * @author Scott Sanders - * @author Marc Johnson - * @version $Id: HexDump.java 596667 2007-11-20 13:50:14Z niallp $ - */ -public class HexDump { - - /** - * Instances should NOT be constructed in standard programming. - */ - public HexDump() { - super(); - } - - /** - * Dump an array of bytes to an OutputStream. - * - * @param data the byte array to be dumped - * @param offset its offset, whatever that might mean - * @param stream the OutputStream to which the data is to be - * written - * @param index initial index into the byte array - * - * @throws IOException is thrown if anything goes wrong writing - * the data to stream - * @throws ArrayIndexOutOfBoundsException if the index is - * outside the data array's bounds - * @throws IllegalArgumentException if the output stream is null - */ - - public static void dump(byte[] data, long offset, - OutputStream stream, int index) - throws IOException, ArrayIndexOutOfBoundsException, - IllegalArgumentException { - - if ((index < 0) || (index >= data.length)) { - throw new ArrayIndexOutOfBoundsException( - "illegal index: " + index + " into array of length " - + data.length); - } - if (stream == null) { - throw new IllegalArgumentException("cannot write to nullstream"); - } - long display_offset = offset + index; - StringBuffer buffer = new StringBuffer(74); - - for (int j = index; j < data.length; j += 16) { - int chars_read = data.length - j; - - if (chars_read > 16) { - chars_read = 16; - } - dump(buffer, display_offset).append(' '); - for (int k = 0; k < 16; k++) { - if (k < chars_read) { - dump(buffer, data[k + j]); - } else { - buffer.append(" "); - } - buffer.append(' '); - } - for (int k = 0; k < chars_read; k++) { - if ((data[k + j] >= ' ') && (data[k + j] < 127)) { - buffer.append((char) data[k + j]); - } else { - buffer.append('.'); - } - } - buffer.append(EOL); - stream.write(buffer.toString().getBytes()); - stream.flush(); - buffer.setLength(0); - display_offset += chars_read; - } - } - - /** - * The line-separator (initializes to "line.separator" system property. - */ - public static final String EOL = - System.getProperty("line.separator"); - private static final char[] _hexcodes = - { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' - }; - private static final int[] _shifts = - { - 28, 24, 20, 16, 12, 8, 4, 0 - }; - - /** - * Dump a long value into a StringBuffer. - * - * @param _lbuffer the StringBuffer to dump the value in - * @param value the long value to be dumped - * @return StringBuffer containing the dumped value. - */ - private static StringBuffer dump(StringBuffer _lbuffer, long value) { - for (int j = 0; j < 8; j++) { - _lbuffer - .append(_hexcodes[((int) (value >> _shifts[j])) & 15]); - } - return _lbuffer; - } - - /** - * Dump a byte value into a StringBuffer. - * - * @param _cbuffer the StringBuffer to dump the value in - * @param value the byte value to be dumped - * @return StringBuffer containing the dumped value. - */ - private static StringBuffer dump(StringBuffer _cbuffer, byte value) { - for (int j = 0; j < 2; j++) { - _cbuffer.append(_hexcodes[(value >> _shifts[j + 6]) & 15]); - } - return _cbuffer; - } - -} diff --git a/src/org/apache/commons/io/IOCase.java b/src/org/apache/commons/io/IOCase.java deleted file mode 100644 index 4230f450d..000000000 --- a/src/org/apache/commons/io/IOCase.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.Serializable; - -/** - * Enumeration of IO case sensitivity. - *

- * Different filing systems have different rules for case-sensitivity. - * Windows is case-insensitive, Unix is case-sensitive. - *

- * This class captures that difference, providing an enumeration to - * control how filename comparisons should be performed. It also provides - * methods that use the enumeration to perform comparisons. - *

- * Wherever possible, you should use the check methods in this - * class to compare filenames. - * - * @author Stephen Colebourne - * @version $Id: IOCase.java 606345 2007-12-21 23:43:01Z ggregory $ - * @since Commons IO 1.3 - */ -public final class IOCase implements Serializable { - - /** - * The constant for case sensitive regardless of operating system. - */ - public static final IOCase SENSITIVE = new IOCase("Sensitive", true); - - /** - * The constant for case insensitive regardless of operating system. - */ - public static final IOCase INSENSITIVE = new IOCase("Insensitive", false); - - /** - * The constant for case sensitivity determined by the current operating system. - * Windows is case-insensitive when comparing filenames, Unix is case-sensitive. - *

- * If you derialize this constant of Windows, and deserialize on Unix, or vice - * versa, then the value of the case-sensitivity flag will change. - */ - public static final IOCase SYSTEM = new IOCase("System", !FilenameUtils.isSystemWindows()); - - /** Serialization version. */ - private static final long serialVersionUID = -6343169151696340687L; - - /** The enumeration name. */ - private final String name; - - /** The sensitivity flag. */ - private final transient boolean sensitive; - - //----------------------------------------------------------------------- - /** - * Factory method to create an IOCase from a name. - * - * @param name the name to find - * @return the IOCase object - * @throws IllegalArgumentException if the name is invalid - */ - public static IOCase forName(String name) { - if (IOCase.SENSITIVE.name.equals(name)){ - return IOCase.SENSITIVE; - } - if (IOCase.INSENSITIVE.name.equals(name)){ - return IOCase.INSENSITIVE; - } - if (IOCase.SYSTEM.name.equals(name)){ - return IOCase.SYSTEM; - } - throw new IllegalArgumentException("Invalid IOCase name: " + name); - } - - //----------------------------------------------------------------------- - /** - * Private constructor. - * - * @param name the name - * @param sensitive the sensitivity - */ - private IOCase(String name, boolean sensitive) { - this.name = name; - this.sensitive = sensitive; - } - - /** - * Replaces the enumeration from the stream with a real one. - * This ensures that the correct flag is set for SYSTEM. - * - * @return the resolved object - */ - private Object readResolve() { - return forName(name); - } - - //----------------------------------------------------------------------- - /** - * Gets the name of the constant. - * - * @return the name of the constant - */ - public String getName() { - return name; - } - - /** - * Does the object represent case sensitive comparison. - * - * @return true if case sensitive - */ - public boolean isCaseSensitive() { - return sensitive; - } - - //----------------------------------------------------------------------- - /** - * Compares two strings using the case-sensitivity rule. - *

- * This method mimics {@link String#compareTo} but takes case-sensitivity - * into account. - * - * @param str1 the first string to compare, not null - * @param str2 the second string to compare, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public int checkCompareTo(String str1, String str2) { - if (str1 == null || str2 == null) { - throw new NullPointerException("The strings must not be null"); - } - return sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2); - } - - /** - * Compares two strings using the case-sensitivity rule. - *

- * This method mimics {@link String#equals} but takes case-sensitivity - * into account. - * - * @param str1 the first string to compare, not null - * @param str2 the second string to compare, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public boolean checkEquals(String str1, String str2) { - if (str1 == null || str2 == null) { - throw new NullPointerException("The strings must not be null"); - } - return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2); - } - - /** - * Checks if one string starts with another using the case-sensitivity rule. - *

- * This method mimics {@link String#startsWith(String)} but takes case-sensitivity - * into account. - * - * @param str the string to check, not null - * @param start the start to compare against, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public boolean checkStartsWith(String str, String start) { - return str.regionMatches(!sensitive, 0, start, 0, start.length()); - } - - /** - * Checks if one string ends with another using the case-sensitivity rule. - *

- * This method mimics {@link String#endsWith} but takes case-sensitivity - * into account. - * - * @param str the string to check, not null - * @param end the end to compare against, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public boolean checkEndsWith(String str, String end) { - int endLen = end.length(); - return str.regionMatches(!sensitive, str.length() - endLen, end, 0, endLen); - } - - /** - * Checks if one string contains another at a specific index using the case-sensitivity rule. - *

- * This method mimics parts of {@link String#regionMatches(boolean, int, String, int, int)} - * but takes case-sensitivity into account. - * - * @param str the string to check, not null - * @param strStartIndex the index to start at in str - * @param search the start to search for, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public boolean checkRegionMatches(String str, int strStartIndex, String search) { - return str.regionMatches(!sensitive, strStartIndex, search, 0, search.length()); - } - - /** - * Converts the case of the input String to a standard format. - * Subsequent operations can then use standard String methods. - * - * @param str the string to convert, null returns null - * @return the lower-case version if case-insensitive - */ - String convertCase(String str) { - if (str == null) { - return null; - } - return sensitive ? str : str.toLowerCase(); - } - - //----------------------------------------------------------------------- - /** - * Gets a string describing the sensitivity. - * - * @return a string describing the sensitivity - */ - public String toString() { - return name; - } - -} diff --git a/src/org/apache/commons/io/IOExceptionWithCause.java b/src/org/apache/commons/io/IOExceptionWithCause.java deleted file mode 100644 index a15815a22..000000000 --- a/src/org/apache/commons/io/IOExceptionWithCause.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.io.IOException; - -/** - * Subclasses IOException with the {@link Throwable} constructors missing before Java 6. If you are using Java 6, - * consider this class deprecated and use {@link IOException}. - * - * @author Apache Commons IO - * @version $Id$ - * @since Commons IO 1.4 - */ -public class IOExceptionWithCause extends IOException { - - /** - * Defines the serial version UID. - */ - private static final long serialVersionUID = 1L; - - /** - * Constructs a new instance with the given message and cause. - *

- * As specified in {@link Throwable}, the message in the given cause is not used in this instance's - * message. - *

- * - * @param message - * the message (see {@link #getMessage()}) - * @param cause - * the cause (see {@link #getCause()}). A null value is allowed. - */ - public IOExceptionWithCause(String message, Throwable cause) { - super(message); - this.initCause(cause); - } - - /** - * Constructs a new instance with the given cause. - *

- * The message is set to cause==null ? null : cause.toString(), which by default contains the class - * and message of cause. This constructor is useful for call sites that just wrap another throwable. - *

- * - * @param cause - * the cause (see {@link #getCause()}). A null value is allowed. - */ - public IOExceptionWithCause(Throwable cause) { - super(cause == null ? null : cause.toString()); - this.initCause(cause); - } - -} diff --git a/src/org/apache/commons/io/IOUtils.java b/src/org/apache/commons/io/IOUtils.java deleted file mode 100644 index 1f91e2562..000000000 --- a/src/org/apache/commons/io/IOUtils.java +++ /dev/null @@ -1,1274 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import org.apache.commons.io.output.ByteArrayOutputStream; - -/** - * General IO stream manipulation utilities. - *

- * This class provides static utility methods for input/output operations. - *

    - *
  • closeQuietly - these methods close a stream ignoring nulls and exceptions - *
  • toXxx/read - these methods read data from a stream - *
  • write - these methods write data to a stream - *
  • copy - these methods copy all the data from one stream to another - *
  • contentEquals - these methods compare the content of two streams - *
- *

- * The byte-to-char methods and char-to-byte methods involve a conversion step. - * Two methods are provided in each case, one that uses the platform default - * encoding and the other which allows you to specify an encoding. You are - * encouraged to always specify an encoding because relying on the platform - * default can lead to unexpected results, for example when moving from - * development to production. - *

- * All the methods in this class that read a stream are buffered internally. - * This means that there is no cause to use a BufferedInputStream - * or BufferedReader. The default buffer size of 4K has been shown - * to be efficient in tests. - *

- * Wherever possible, the methods in this class do not flush or close - * the stream. This is to avoid making non-portable assumptions about the - * streams' origin and further use. Thus the caller is still responsible for - * closing streams after use. - *

- * Origin of code: Excalibur. - * - * @author Peter Donald - * @author Jeff Turner - * @author Matthew Hawthorne - * @author Stephen Colebourne - * @author Gareth Davis - * @author Ian Springer - * @author Niall Pemberton - * @author Sandy McArthur - * @version $Id: IOUtils.java 481854 2006-12-03 18:30:07Z scolebourne $ - */ -public class IOUtils { - // NOTE: This class is focussed on InputStream, OutputStream, Reader and - // Writer. Each method should take at least one of these as a parameter, - // or return one of them. - - /** - * The Unix directory separator character. - */ - public static final char DIR_SEPARATOR_UNIX = '/'; - /** - * The Windows directory separator character. - */ - public static final char DIR_SEPARATOR_WINDOWS = '\\'; - /** - * The system directory separator character. - */ - public static final char DIR_SEPARATOR = File.separatorChar; - /** - * The Unix line separator string. - */ - public static final String LINE_SEPARATOR_UNIX = "\n"; - /** - * The Windows line separator string. - */ - public static final String LINE_SEPARATOR_WINDOWS = "\r\n"; - /** - * The system line separator string. - */ - public static final String LINE_SEPARATOR; - static { - // avoid security issues - StringWriter buf = new StringWriter(4); - PrintWriter out = new PrintWriter(buf); - out.println(); - LINE_SEPARATOR = buf.toString(); - } - - /** - * The default buffer size to use. - */ - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - - /** - * Instances should NOT be constructed in standard programming. - */ - public IOUtils() { - super(); - } - - //----------------------------------------------------------------------- - /** - * Unconditionally close an Reader. - *

- * Equivalent to {@link Reader#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param input the Reader to close, may be null or already closed - */ - public static void closeQuietly(Reader input) { - try { - if (input != null) { - input.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - /** - * Unconditionally close a Writer. - *

- * Equivalent to {@link Writer#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param output the Writer to close, may be null or already closed - */ - public static void closeQuietly(Writer output) { - try { - if (output != null) { - output.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - /** - * Unconditionally close an InputStream. - *

- * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param input the InputStream to close, may be null or already closed - */ - public static void closeQuietly(InputStream input) { - try { - if (input != null) { - input.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - /** - * Unconditionally close an OutputStream. - *

- * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param output the OutputStream to close, may be null or already closed - */ - public static void closeQuietly(OutputStream output) { - try { - if (output != null) { - output.close(); - } - } catch (IOException ioe) { - // ignore - } - } - - // read toByteArray - //----------------------------------------------------------------------- - /** - * Get the contents of an InputStream as a byte[]. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static byte[] toByteArray(InputStream input) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output); - return output.toByteArray(); - } - - /** - * Get the contents of a Reader as a byte[] - * using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - * - * @param input the Reader to read from - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static byte[] toByteArray(Reader input) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output); - return output.toByteArray(); - } - - /** - * Get the contents of a Reader as a byte[] - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - * - * @param input the Reader to read from - * @param encoding the encoding to use, null means platform default - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static byte[] toByteArray(Reader input, String encoding) - throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output, encoding); - return output.toByteArray(); - } - - /** - * Get the contents of a String as a byte[] - * using the default character encoding of the platform. - *

- * This is the same as {@link String#getBytes()}. - * - * @param input the String to convert - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs (never occurs) - * @deprecated Use {@link String#getBytes()} - */ - public static byte[] toByteArray(String input) throws IOException { - return input.getBytes(); - } - - // read char[] - //----------------------------------------------------------------------- - /** - * Get the contents of an InputStream as a character array - * using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param is the InputStream to read from - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static char[] toCharArray(InputStream is) throws IOException { - CharArrayWriter output = new CharArrayWriter(); - copy(is, output); - return output.toCharArray(); - } - - /** - * Get the contents of an InputStream as a character array - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param is the InputStream to read from - * @param encoding the encoding to use, null means platform default - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static char[] toCharArray(InputStream is, String encoding) - throws IOException { - CharArrayWriter output = new CharArrayWriter(); - copy(is, output, encoding); - return output.toCharArray(); - } - - /** - * Get the contents of a Reader as a character array. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - * - * @param input the Reader to read from - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static char[] toCharArray(Reader input) throws IOException { - CharArrayWriter sw = new CharArrayWriter(); - copy(input, sw); - return sw.toCharArray(); - } - - // read toString - //----------------------------------------------------------------------- - /** - * Get the contents of an InputStream as a String - * using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static String toString(InputStream input) throws IOException { - StringWriter sw = new StringWriter(); - copy(input, sw); - return sw.toString(); - } - - /** - * Get the contents of an InputStream as a String - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from - * @param encoding the encoding to use, null means platform default - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static String toString(InputStream input, String encoding) - throws IOException { - StringWriter sw = new StringWriter(); - copy(input, sw, encoding); - return sw.toString(); - } - - /** - * Get the contents of a Reader as a String. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - * - * @param input the Reader to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static String toString(Reader input) throws IOException { - StringWriter sw = new StringWriter(); - copy(input, sw); - return sw.toString(); - } - - /** - * Get the contents of a byte[] as a String - * using the default character encoding of the platform. - * - * @param input the byte array to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs (never occurs) - * @deprecated Use {@link String#String(byte[])} - */ - public static String toString(byte[] input) throws IOException { - return new String(input); - } - - /** - * Get the contents of a byte[] as a String - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - * - * @param input the byte array to read from - * @param encoding the encoding to use, null means platform default - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs (never occurs) - * @deprecated Use {@link String#String(byte[],String)} - */ - public static String toString(byte[] input, String encoding) - throws IOException { - if (encoding == null) { - return new String(input); - } else { - return new String(input, encoding); - } - } - - // readLines - //----------------------------------------------------------------------- - /** - * Get the contents of an InputStream as a list of Strings, - * one entry per line, using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from, not null - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static List readLines(InputStream input) throws IOException { - InputStreamReader reader = new InputStreamReader(input); - return readLines(reader); - } - - /** - * Get the contents of an InputStream as a list of Strings, - * one entry per line, using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from, not null - * @param encoding the encoding to use, null means platform default - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static List readLines(InputStream input, String encoding) throws IOException { - if (encoding == null) { - return readLines(input); - } else { - InputStreamReader reader = new InputStreamReader(input, encoding); - return readLines(reader); - } - } - - /** - * Get the contents of a Reader as a list of Strings, - * one entry per line. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - * - * @param input the Reader to read from, not null - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static List readLines(Reader input) throws IOException { - BufferedReader reader = new BufferedReader(input); - List list = new ArrayList(); - String line = reader.readLine(); - while (line != null) { - list.add(line); - line = reader.readLine(); - } - return list; - } - - // lineIterator - //----------------------------------------------------------------------- - /** - * Return an Iterator for the lines in a Reader. - *

- * LineIterator holds a reference to the open - * Reader specified here. When you have finished with the - * iterator you should close the reader to free internal resources. - * This can be done by closing the reader directly, or by calling - * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}. - *

- * The recommended usage pattern is: - *

-     * try {
-     *   LineIterator it = IOUtils.lineIterator(reader);
-     *   while (it.hasNext()) {
-     *     String line = it.nextLine();
-     *     /// do something with line
-     *   }
-     * } finally {
-     *   IOUtils.closeQuietly(reader);
-     * }
-     * 
- * - * @param reader the Reader to read from, not null - * @return an Iterator of the lines in the reader, never null - * @throws IllegalArgumentException if the reader is null - * @since Commons IO 1.2 - */ - public static LineIterator lineIterator(Reader reader) { - return new LineIterator(reader); - } - - /** - * Return an Iterator for the lines in an InputStream, using - * the character encoding specified (or default encoding if null). - *

- * LineIterator holds a reference to the open - * InputStream specified here. When you have finished with - * the iterator you should close the stream to free internal resources. - * This can be done by closing the stream directly, or by calling - * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}. - *

- * The recommended usage pattern is: - *

-     * try {
-     *   LineIterator it = IOUtils.lineIterator(stream, "UTF-8");
-     *   while (it.hasNext()) {
-     *     String line = it.nextLine();
-     *     /// do something with line
-     *   }
-     * } finally {
-     *   IOUtils.closeQuietly(stream);
-     * }
-     * 
- * - * @param input the InputStream to read from, not null - * @param encoding the encoding to use, null means platform default - * @return an Iterator of the lines in the reader, never null - * @throws IllegalArgumentException if the input is null - * @throws IOException if an I/O error occurs, such as if the encoding is invalid - * @since Commons IO 1.2 - */ - public static LineIterator lineIterator(InputStream input, String encoding) - throws IOException { - Reader reader = null; - if (encoding == null) { - reader = new InputStreamReader(input); - } else { - reader = new InputStreamReader(input, encoding); - } - return new LineIterator(reader); - } - - //----------------------------------------------------------------------- - /** - * Convert the specified string to an input stream, encoded as bytes - * using the default character encoding of the platform. - * - * @param input the string to convert - * @return an input stream - * @since Commons IO 1.1 - */ - public static InputStream toInputStream(String input) { - byte[] bytes = input.getBytes(); - return new ByteArrayInputStream(bytes); - } - - /** - * Convert the specified string to an input stream, encoded as bytes - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - * - * @param input the string to convert - * @param encoding the encoding to use, null means platform default - * @throws IOException if the encoding is invalid - * @return an input stream - * @since Commons IO 1.1 - */ - public static InputStream toInputStream(String input, String encoding) throws IOException { - byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes(); - return new ByteArrayInputStream(bytes); - } - - // write byte[] - //----------------------------------------------------------------------- - /** - * Writes bytes from a byte[] to an OutputStream. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the OutputStream to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(byte[] data, OutputStream output) - throws IOException { - if (data != null) { - output.write(data); - } - } - - /** - * Writes bytes from a byte[] to chars on a Writer - * using the default character encoding of the platform. - *

- * This method uses {@link String#String(byte[])}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the Writer to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(byte[] data, Writer output) throws IOException { - if (data != null) { - output.write(new String(data)); - } - } - - /** - * Writes bytes from a byte[] to chars on a Writer - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#String(byte[], String)}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the Writer to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(byte[] data, Writer output, String encoding) - throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(new String(data, encoding)); - } - } - } - - // write char[] - //----------------------------------------------------------------------- - /** - * Writes chars from a char[] to a Writer - * using the default character encoding of the platform. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the Writer to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(char[] data, Writer output) throws IOException { - if (data != null) { - output.write(data); - } - } - - /** - * Writes chars from a char[] to bytes on an - * OutputStream. - *

- * This method uses {@link String#String(char[])} and - * {@link String#getBytes()}. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the OutputStream to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(char[] data, OutputStream output) - throws IOException { - if (data != null) { - output.write(new String(data).getBytes()); - } - } - - /** - * Writes chars from a char[] to bytes on an - * OutputStream using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#String(char[])} and - * {@link String#getBytes(String)}. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the OutputStream to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(char[] data, OutputStream output, String encoding) - throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(new String(data).getBytes(encoding)); - } - } - } - - // write String - //----------------------------------------------------------------------- - /** - * Writes chars from a String to a Writer. - * - * @param data the String to write, null ignored - * @param output the Writer to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(String data, Writer output) throws IOException { - if (data != null) { - output.write(data); - } - } - - /** - * Writes chars from a String to bytes on an - * OutputStream using the default character encoding of the - * platform. - *

- * This method uses {@link String#getBytes()}. - * - * @param data the String to write, null ignored - * @param output the OutputStream to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(String data, OutputStream output) - throws IOException { - if (data != null) { - output.write(data.getBytes()); - } - } - - /** - * Writes chars from a String to bytes on an - * OutputStream using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#getBytes(String)}. - * - * @param data the String to write, null ignored - * @param output the OutputStream to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(String data, OutputStream output, String encoding) - throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(data.getBytes(encoding)); - } - } - } - - // write StringBuffer - //----------------------------------------------------------------------- - /** - * Writes chars from a StringBuffer to a Writer. - * - * @param data the StringBuffer to write, null ignored - * @param output the Writer to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(StringBuffer data, Writer output) - throws IOException { - if (data != null) { - output.write(data.toString()); - } - } - - /** - * Writes chars from a StringBuffer to bytes on an - * OutputStream using the default character encoding of the - * platform. - *

- * This method uses {@link String#getBytes()}. - * - * @param data the StringBuffer to write, null ignored - * @param output the OutputStream to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(StringBuffer data, OutputStream output) - throws IOException { - if (data != null) { - output.write(data.toString().getBytes()); - } - } - - /** - * Writes chars from a StringBuffer to bytes on an - * OutputStream using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#getBytes(String)}. - * - * @param data the StringBuffer to write, null ignored - * @param output the OutputStream to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void write(StringBuffer data, OutputStream output, - String encoding) throws IOException { - if (data != null) { - if (encoding == null) { - write(data, output); - } else { - output.write(data.toString().getBytes(encoding)); - } - } - } - - // writeLines - //----------------------------------------------------------------------- - /** - * Writes the toString() value of each item in a collection to - * an OutputStream line by line, using the default character - * encoding of the platform and the specified line ending. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param output the OutputStream to write to, not null, not closed - * @throws NullPointerException if the output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void writeLines(Collection lines, String lineEnding, - OutputStream output) throws IOException { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = LINE_SEPARATOR; - } - for (Iterator it = lines.iterator(); it.hasNext(); ) { - Object line = it.next(); - if (line != null) { - output.write(line.toString().getBytes()); - } - output.write(lineEnding.getBytes()); - } - } - - /** - * Writes the toString() value of each item in a collection to - * an OutputStream line by line, using the specified character - * encoding and the specified line ending. - *

- * Character encoding names can be found at - * IANA. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param output the OutputStream to write to, not null, not closed - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if the output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void writeLines(Collection lines, String lineEnding, - OutputStream output, String encoding) throws IOException { - if (encoding == null) { - writeLines(lines, lineEnding, output); - } else { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = LINE_SEPARATOR; - } - for (Iterator it = lines.iterator(); it.hasNext(); ) { - Object line = it.next(); - if (line != null) { - output.write(line.toString().getBytes(encoding)); - } - output.write(lineEnding.getBytes(encoding)); - } - } - } - - /** - * Writes the toString() value of each item in a collection to - * a Writer line by line, using the specified line ending. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param writer the Writer to write to, not null, not closed - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void writeLines(Collection lines, String lineEnding, - Writer writer) throws IOException { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = LINE_SEPARATOR; - } - for (Iterator it = lines.iterator(); it.hasNext(); ) { - Object line = it.next(); - if (line != null) { - writer.write(line.toString()); - } - writer.write(lineEnding); - } - } - - // copy from InputStream - //----------------------------------------------------------------------- - /** - * Copy bytes from an InputStream to an - * OutputStream. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - *

- * Large streams (over 2GB) will return a bytes copied value of - * -1 after the copy has completed since the correct - * number of bytes cannot be returned as an int. For large streams - * use the copyLarge(InputStream, OutputStream) method. - * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @throws ArithmeticException if the byte count is too large - * @since Commons IO 1.1 - */ - public static int copy(InputStream input, OutputStream output) throws IOException { - long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } - - /** - * Copy bytes from a large (over 2GB) InputStream to an - * OutputStream. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.3 - */ - public static long copyLarge(InputStream input, OutputStream output) - throws IOException { - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - long count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Copy bytes from an InputStream to chars on a - * Writer using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - *

- * This method uses {@link InputStreamReader}. - * - * @param input the InputStream to read from - * @param output the Writer to write to - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(InputStream input, Writer output) - throws IOException { - InputStreamReader in = new InputStreamReader(input); - copy(in, output); - } - - /** - * Copy bytes from an InputStream to chars on a - * Writer using the specified character encoding. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link InputStreamReader}. - * - * @param input the InputStream to read from - * @param output the Writer to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(InputStream input, Writer output, String encoding) - throws IOException { - if (encoding == null) { - copy(input, output); - } else { - InputStreamReader in = new InputStreamReader(input, encoding); - copy(in, output); - } - } - - // copy from Reader - //----------------------------------------------------------------------- - /** - * Copy chars from a Reader to a Writer. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - *

- * Large streams (over 2GB) will return a chars copied value of - * -1 after the copy has completed since the correct - * number of chars cannot be returned as an int. For large streams - * use the copyLarge(Reader, Writer) method. - * - * @param input the Reader to read from - * @param output the Writer to write to - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @throws ArithmeticException if the character count is too large - * @since Commons IO 1.1 - */ - public static int copy(Reader input, Writer output) throws IOException { - long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } - - /** - * Copy chars from a large (over 2GB) Reader to a Writer. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - * - * @param input the Reader to read from - * @param output the Writer to write to - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.3 - */ - public static long copyLarge(Reader input, Writer output) throws IOException { - char[] buffer = new char[DEFAULT_BUFFER_SIZE]; - long count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Copy chars from a Reader to bytes on an - * OutputStream using the default character encoding of the - * platform, and calling flush. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - *

- * Due to the implementation of OutputStreamWriter, this method performs a - * flush. - *

- * This method uses {@link OutputStreamWriter}. - * - * @param input the Reader to read from - * @param output the OutputStream to write to - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(Reader input, OutputStream output) - throws IOException { - OutputStreamWriter out = new OutputStreamWriter(output); - copy(input, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - /** - * Copy chars from a Reader to bytes on an - * OutputStream using the specified character encoding, and - * calling flush. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - *

- * Character encoding names can be found at - * IANA. - *

- * Due to the implementation of OutputStreamWriter, this method performs a - * flush. - *

- * This method uses {@link OutputStreamWriter}. - * - * @param input the Reader to read from - * @param output the OutputStream to write to - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(Reader input, OutputStream output, String encoding) - throws IOException { - if (encoding == null) { - copy(input, output); - } else { - OutputStreamWriter out = new OutputStreamWriter(output, encoding); - copy(input, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, - // we have to flush here. - out.flush(); - } - } - - // content equals - //----------------------------------------------------------------------- - /** - * Compare the contents of two Streams to determine if they are equal or - * not. - *

- * This method buffers the input internally using - * BufferedInputStream if they are not already buffered. - * - * @param input1 the first stream - * @param input2 the second stream - * @return true if the content of the streams are equal or they both don't - * exist, false otherwise - * @throws NullPointerException if either input is null - * @throws IOException if an I/O error occurs - */ - public static boolean contentEquals(InputStream input1, InputStream input2) - throws IOException { - if (!(input1 instanceof BufferedInputStream)) { - input1 = new BufferedInputStream(input1); - } - if (!(input2 instanceof BufferedInputStream)) { - input2 = new BufferedInputStream(input2); - } - - int ch = input1.read(); - while (-1 != ch) { - int ch2 = input2.read(); - if (ch != ch2) { - return false; - } - ch = input1.read(); - } - - int ch2 = input2.read(); - return (ch2 == -1); - } - - /** - * Compare the contents of two Readers to determine if they are equal or - * not. - *

- * This method buffers the input internally using - * BufferedReader if they are not already buffered. - * - * @param input1 the first reader - * @param input2 the second reader - * @return true if the content of the readers are equal or they both don't - * exist, false otherwise - * @throws NullPointerException if either input is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static boolean contentEquals(Reader input1, Reader input2) - throws IOException { - if (!(input1 instanceof BufferedReader)) { - input1 = new BufferedReader(input1); - } - if (!(input2 instanceof BufferedReader)) { - input2 = new BufferedReader(input2); - } - - int ch = input1.read(); - while (-1 != ch) { - int ch2 = input2.read(); - if (ch != ch2) { - return false; - } - ch = input1.read(); - } - - int ch2 = input2.read(); - return (ch2 == -1); - } - -} diff --git a/src/org/apache/commons/io/LineIterator.java b/src/org/apache/commons/io/LineIterator.java deleted file mode 100644 index eac47d23a..000000000 --- a/src/org/apache/commons/io/LineIterator.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * An Iterator over the lines in a Reader. - *

- * LineIterator holds a reference to an open Reader. - * When you have finished with the iterator you should close the reader - * to free internal resources. This can be done by closing the reader directly, - * or by calling the {@link #close()} or {@link #closeQuietly(LineIterator)} - * method on the iterator. - *

- * The recommended usage pattern is: - *

- * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
- * try {
- *   while (it.hasNext()) {
- *     String line = it.nextLine();
- *     /// do something with line
- *   }
- * } finally {
- *   LineIterator.closeQuietly(iterator);
- * }
- * 
- * - * @author Niall Pemberton - * @author Stephen Colebourne - * @author Sandy McArthur - * @version $Id: LineIterator.java 437567 2006-08-28 06:39:07Z bayard $ - * @since Commons IO 1.2 - */ -public class LineIterator implements Iterator { - - /** The reader that is being read. */ - private final BufferedReader bufferedReader; - /** The current line. */ - private String cachedLine; - /** A flag indicating if the iterator has been fully read. */ - private boolean finished = false; - - /** - * Constructs an iterator of the lines for a Reader. - * - * @param reader the Reader to read from, not null - * @throws IllegalArgumentException if the reader is null - */ - public LineIterator(final Reader reader) throws IllegalArgumentException { - if (reader == null) { - throw new IllegalArgumentException("Reader must not be null"); - } - if (reader instanceof BufferedReader) { - bufferedReader = (BufferedReader) reader; - } else { - bufferedReader = new BufferedReader(reader); - } - } - - //----------------------------------------------------------------------- - /** - * Indicates whether the Reader has more lines. - * If there is an IOException then {@link #close()} will - * be called on this instance. - * - * @return true if the Reader has more lines - * @throws IllegalStateException if an IO exception occurs - */ - public boolean hasNext() { - if (cachedLine != null) { - return true; - } else if (finished) { - return false; - } else { - try { - while (true) { - String line = bufferedReader.readLine(); - if (line == null) { - finished = true; - return false; - } else if (isValidLine(line)) { - cachedLine = line; - return true; - } - } - } catch(IOException ioe) { - close(); - throw new IllegalStateException(ioe.toString()); - } - } - } - - /** - * Overridable method to validate each line that is returned. - * - * @param line the line that is to be validated - * @return true if valid, false to remove from the iterator - */ - protected boolean isValidLine(String line) { - return true; - } - - /** - * Returns the next line in the wrapped Reader. - * - * @return the next line from the input - * @throws NoSuchElementException if there is no line to return - */ - public Object next() { - return nextLine(); - } - - /** - * Returns the next line in the wrapped Reader. - * - * @return the next line from the input - * @throws NoSuchElementException if there is no line to return - */ - public String nextLine() { - if (!hasNext()) { - throw new NoSuchElementException("No more lines"); - } - String currentLine = cachedLine; - cachedLine = null; - return currentLine; - } - - /** - * Closes the underlying Reader quietly. - * This method is useful if you only want to process the first few - * lines of a larger file. If you do not close the iterator - * then the Reader remains open. - * This method can safely be called multiple times. - */ - public void close() { - finished = true; - IOUtils.closeQuietly(bufferedReader); - cachedLine = null; - } - - /** - * Unsupported. - * - * @throws UnsupportedOperationException always - */ - public void remove() { - throw new UnsupportedOperationException("Remove unsupported on LineIterator"); - } - - //----------------------------------------------------------------------- - /** - * Closes the iterator, handling null and ignoring exceptions. - * - * @param iterator the iterator to close - */ - public static void closeQuietly(LineIterator iterator) { - if (iterator != null) { - iterator.close(); - } - } - -} diff --git a/src/org/apache/commons/io/comparator/DefaultFileComparator.java b/src/org/apache/commons/io/comparator/DefaultFileComparator.java deleted file mode 100644 index d36076288..000000000 --- a/src/org/apache/commons/io/comparator/DefaultFileComparator.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.comparator; - -import java.io.File; -import java.io.Serializable; -import java.util.Comparator; - -/** - * Compare two files using the default {@link File#compareTo(File)} method. - *

- * This comparator can be used to sort lists or arrays of files - * by using the default file comparison. - *

- * Example of sorting a list of files using the - * {@link #DEFAULT_COMPARATOR} singleton instance: - *

- *       List<File> list = ...
- *       Collections.sort(list, DefaultFileComparator.DEFAULT_COMPARATOR);
- * 
- *

- * Example of doing a reverse sort of an array of files using the - * {@link #DEFAULT_REVERSE} singleton instance: - *

- *       File[] array = ...
- *       Arrays.sort(array, DefaultFileComparator.DEFAULT_REVERSE);
- * 
- *

- * - * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $ - * @since Commons IO 1.4 - */ -public class DefaultFileComparator implements Comparator, Serializable { - - /** Singleton default comparator instance */ - public static final Comparator DEFAULT_COMPARATOR = new DefaultFileComparator(); - - /** Singleton reverse default comparator instance */ - public static final Comparator DEFAULT_REVERSE = new ReverseComparator(DEFAULT_COMPARATOR); - - /** - * Compare the two files using the {@link File#compareTo(File)} method. - * - * @param obj1 The first file to compare - * @param obj2 The second file to compare - * @return the result of calling file1's - * {@link File#compareTo(File)} with file2 as the parameter. - */ - public int compare(Object obj1, Object obj2) { - File file1 = (File)obj1; - File file2 = (File)obj2; - return file1.compareTo(file2); - } -} diff --git a/src/org/apache/commons/io/comparator/ExtensionFileComparator.java b/src/org/apache/commons/io/comparator/ExtensionFileComparator.java deleted file mode 100644 index 158480fb3..000000000 --- a/src/org/apache/commons/io/comparator/ExtensionFileComparator.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.comparator; - -import java.io.File; -import java.io.Serializable; -import java.util.Comparator; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOCase; - -/** - * Compare the file name extensions for order - * (see {@link FilenameUtils#getExtension(String)}). - *

- * This comparator can be used to sort lists or arrays of files - * by their file extension either in a case-sensitive, case-insensitive or - * system dependant case sensitive way. A number of singleton instances - * are provided for the various case sensitivity options (using {@link IOCase}) - * and the reverse of those options. - *

- * Example of a case-sensitive file extension sort using the - * {@link #EXTENSION_COMPARATOR} singleton instance: - *

- *       List<File> list = ...
- *       Collections.sort(list, ExtensionFileComparator.EXTENSION_COMPARATOR);
- * 
- *

- * Example of a reverse case-insensitive file extension sort using the - * {@link #EXTENSION_INSENSITIVE_REVERSE} singleton instance: - *

- *       File[] array = ...
- *       Arrays.sort(array, ExtensionFileComparator.EXTENSION_INSENSITIVE_REVERSE);
- * 
- *

- * - * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $ - * @since Commons IO 1.4 - */ -public class ExtensionFileComparator implements Comparator, Serializable { - - /** Case-sensitive extension comparator instance (see {@link IOCase#SENSITIVE}) */ - public static final Comparator EXTENSION_COMPARATOR = new ExtensionFileComparator(); - - /** Reverse case-sensitive extension comparator instance (see {@link IOCase#SENSITIVE}) */ - public static final Comparator EXTENSION_REVERSE = new ReverseComparator(EXTENSION_COMPARATOR); - - /** Case-insensitive extension comparator instance (see {@link IOCase#INSENSITIVE}) */ - public static final Comparator EXTENSION_INSENSITIVE_COMPARATOR = new ExtensionFileComparator(IOCase.INSENSITIVE); - - /** Reverse case-insensitive extension comparator instance (see {@link IOCase#INSENSITIVE}) */ - public static final Comparator EXTENSION_INSENSITIVE_REVERSE - = new ReverseComparator(EXTENSION_INSENSITIVE_COMPARATOR); - - /** System sensitive extension comparator instance (see {@link IOCase#SYSTEM}) */ - public static final Comparator EXTENSION_SYSTEM_COMPARATOR = new ExtensionFileComparator(IOCase.SYSTEM); - - /** Reverse system sensitive path comparator instance (see {@link IOCase#SYSTEM}) */ - public static final Comparator EXTENSION_SYSTEM_REVERSE = new ReverseComparator(EXTENSION_SYSTEM_COMPARATOR); - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Construct a case sensitive file extension comparator instance. - */ - public ExtensionFileComparator() { - this.caseSensitivity = IOCase.SENSITIVE; - } - - /** - * Construct a file extension comparator instance with the specified case-sensitivity. - * - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - */ - public ExtensionFileComparator(IOCase caseSensitivity) { - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Compare the extensions of two files the specified case sensitivity. - * - * @param obj1 The first file to compare - * @param obj2 The second file to compare - * @return a negative value if the first file's extension - * is less than the second, zero if the extensions are the - * same and a positive value if the first files extension - * is greater than the second file. - * - */ - public int compare(Object obj1, Object obj2) { - File file1 = (File)obj1; - File file2 = (File)obj2; - String suffix1 = FilenameUtils.getExtension(file1.getName()); - String suffix2 = FilenameUtils.getExtension(file2.getName()); - return caseSensitivity.checkCompareTo(suffix1, suffix2); - } -} diff --git a/src/org/apache/commons/io/comparator/LastModifiedFileComparator.java b/src/org/apache/commons/io/comparator/LastModifiedFileComparator.java deleted file mode 100644 index 8265023d0..000000000 --- a/src/org/apache/commons/io/comparator/LastModifiedFileComparator.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.comparator; - -import java.io.File; -import java.io.Serializable; -import java.util.Comparator; - -/** - * Compare the last modified date/time of two files for order - * (see {@link File#lastModified()}). - *

- * This comparator can be used to sort lists or arrays of files - * by their last modified date/time. - *

- * Example of sorting a list of files using the - * {@link #LASTMODIFIED_COMPARATOR} singleton instance: - *

- *       List<File> list = ...
- *       Collections.sort(list, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
- * 
- *

- * Example of doing a reverse sort of an array of files using the - * {@link #LASTMODIFIED_REVERSE} singleton instance: - *

- *       File[] array = ...
- *       Arrays.sort(array, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
- * 
- *

- * - * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $ - * @since Commons IO 1.4 - */ -public class LastModifiedFileComparator implements Comparator, Serializable { - - /** Last modified comparator instance */ - public static final Comparator LASTMODIFIED_COMPARATOR = new LastModifiedFileComparator(); - - /** Reverse last modified comparator instance */ - public static final Comparator LASTMODIFIED_REVERSE = new ReverseComparator(LASTMODIFIED_COMPARATOR); - - /** - * Compare the last the last modified date/time of two files. - * - * @param obj1 The first file to compare - * @param obj2 The second file to compare - * @return a negative value if the first file's lastmodified date/time - * is less than the second, zero if the lastmodified date/time are the - * same and a positive value if the first files lastmodified date/time - * is greater than the second file. - * - */ - public int compare(Object obj1, Object obj2) { - File file1 = (File)obj1; - File file2 = (File)obj2; - long result = file1.lastModified() - file2.lastModified(); - if (result < 0) { - return -1; - } else if (result > 0) { - return 1; - } else { - return 0; - } - } -} diff --git a/src/org/apache/commons/io/comparator/NameFileComparator.java b/src/org/apache/commons/io/comparator/NameFileComparator.java deleted file mode 100644 index 76af21eeb..000000000 --- a/src/org/apache/commons/io/comparator/NameFileComparator.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.comparator; - -import java.io.File; -import java.io.Serializable; -import java.util.Comparator; - -import org.apache.commons.io.IOCase; - -/** - * Compare the names of two files for order (see {@link File#getName()}). - *

- * This comparator can be used to sort lists or arrays of files - * by their name either in a case-sensitive, case-insensitive or - * system dependant case sensitive way. A number of singleton instances - * are provided for the various case sensitivity options (using {@link IOCase}) - * and the reverse of those options. - *

- * Example of a case-sensitive file name sort using the - * {@link #NAME_COMPARATOR} singleton instance: - *

- *       List<File> list = ...
- *       Collections.sort(list, NameFileComparator.NAME_COMPARATOR);
- * 
- *

- * Example of a reverse case-insensitive file name sort using the - * {@link #NAME_INSENSITIVE_REVERSE} singleton instance: - *

- *       File[] array = ...
- *       Arrays.sort(array, NameFileComparator.NAME_INSENSITIVE_REVERSE);
- * 
- *

- * - * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $ - * @since Commons IO 1.4 - */ -public class NameFileComparator implements Comparator, Serializable { - - /** Case-sensitive name comparator instance (see {@link IOCase#SENSITIVE}) */ - public static final Comparator NAME_COMPARATOR = new NameFileComparator(); - - /** Reverse case-sensitive name comparator instance (see {@link IOCase#SENSITIVE}) */ - public static final Comparator NAME_REVERSE = new ReverseComparator(NAME_COMPARATOR); - - /** Case-insensitive name comparator instance (see {@link IOCase#INSENSITIVE}) */ - public static final Comparator NAME_INSENSITIVE_COMPARATOR = new NameFileComparator(IOCase.INSENSITIVE); - - /** Reverse case-insensitive name comparator instance (see {@link IOCase#INSENSITIVE}) */ - public static final Comparator NAME_INSENSITIVE_REVERSE = new ReverseComparator(NAME_INSENSITIVE_COMPARATOR); - - /** System sensitive name comparator instance (see {@link IOCase#SYSTEM}) */ - public static final Comparator NAME_SYSTEM_COMPARATOR = new NameFileComparator(IOCase.SYSTEM); - - /** Reverse system sensitive name comparator instance (see {@link IOCase#SYSTEM}) */ - public static final Comparator NAME_SYSTEM_REVERSE = new ReverseComparator(NAME_SYSTEM_COMPARATOR); - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Construct a case sensitive file name comparator instance. - */ - public NameFileComparator() { - this.caseSensitivity = IOCase.SENSITIVE; - } - - /** - * Construct a file name comparator instance with the specified case-sensitivity. - * - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - */ - public NameFileComparator(IOCase caseSensitivity) { - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Compare the names of two files with the specified case sensitivity. - * - * @param obj1 The first file to compare - * @param obj2 The second file to compare - * @return a negative value if the first file's name - * is less than the second, zero if the names are the - * same and a positive value if the first files name - * is greater than the second file. - */ - public int compare(Object obj1, Object obj2) { - File file1 = (File)obj1; - File file2 = (File)obj2; - return caseSensitivity.checkCompareTo(file1.getName(), file2.getName()); - } -} diff --git a/src/org/apache/commons/io/comparator/PathFileComparator.java b/src/org/apache/commons/io/comparator/PathFileComparator.java deleted file mode 100644 index 0b28b6960..000000000 --- a/src/org/apache/commons/io/comparator/PathFileComparator.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.comparator; - -import java.io.File; -import java.io.Serializable; -import java.util.Comparator; - -import org.apache.commons.io.IOCase; - -/** - * Compare the path of two files for order (see {@link File#getPath()}). - *

- * This comparator can be used to sort lists or arrays of files - * by their path either in a case-sensitive, case-insensitive or - * system dependant case sensitive way. A number of singleton instances - * are provided for the various case sensitivity options (using {@link IOCase}) - * and the reverse of those options. - *

- * Example of a case-sensitive file path sort using the - * {@link #PATH_COMPARATOR} singleton instance: - *

- *       List<File> list = ...
- *       Collections.sort(list, PathFileComparator.PATH_COMPARATOR);
- * 
- *

- * Example of a reverse case-insensitive file path sort using the - * {@link #PATH_INSENSITIVE_REVERSE} singleton instance: - *

- *       File[] array = ...
- *       Arrays.sort(array, PathFileComparator.PATH_INSENSITIVE_REVERSE);
- * 
- *

- * - * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $ - * @since Commons IO 1.4 - */ -public class PathFileComparator implements Comparator, Serializable { - - /** Case-sensitive path comparator instance (see {@link IOCase#SENSITIVE}) */ - public static final Comparator PATH_COMPARATOR = new PathFileComparator(); - - /** Reverse case-sensitive path comparator instance (see {@link IOCase#SENSITIVE}) */ - public static final Comparator PATH_REVERSE = new ReverseComparator(PATH_COMPARATOR); - - /** Case-insensitive path comparator instance (see {@link IOCase#INSENSITIVE}) */ - public static final Comparator PATH_INSENSITIVE_COMPARATOR = new PathFileComparator(IOCase.INSENSITIVE); - - /** Reverse case-insensitive path comparator instance (see {@link IOCase#INSENSITIVE}) */ - public static final Comparator PATH_INSENSITIVE_REVERSE = new ReverseComparator(PATH_INSENSITIVE_COMPARATOR); - - /** System sensitive path comparator instance (see {@link IOCase#SYSTEM}) */ - public static final Comparator PATH_SYSTEM_COMPARATOR = new PathFileComparator(IOCase.SYSTEM); - - /** Reverse system sensitive path comparator instance (see {@link IOCase#SYSTEM}) */ - public static final Comparator PATH_SYSTEM_REVERSE = new ReverseComparator(PATH_SYSTEM_COMPARATOR); - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Construct a case sensitive file path comparator instance. - */ - public PathFileComparator() { - this.caseSensitivity = IOCase.SENSITIVE; - } - - /** - * Construct a file path comparator instance with the specified case-sensitivity. - * - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - */ - public PathFileComparator(IOCase caseSensitivity) { - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Compare the paths of two files the specified case sensitivity. - * - * @param obj1 The first file to compare - * @param obj2 The second file to compare - * @return a negative value if the first file's path - * is less than the second, zero if the paths are the - * same and a positive value if the first files path - * is greater than the second file. - * - */ - public int compare(Object obj1, Object obj2) { - File file1 = (File)obj1; - File file2 = (File)obj2; - return caseSensitivity.checkCompareTo(file1.getPath(), file2.getPath()); - } -} diff --git a/src/org/apache/commons/io/comparator/ReverseComparator.java b/src/org/apache/commons/io/comparator/ReverseComparator.java deleted file mode 100644 index af9749ee3..000000000 --- a/src/org/apache/commons/io/comparator/ReverseComparator.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.comparator; - -import java.io.Serializable; -import java.util.Comparator; - -/** - * Reverses the result of comparing two objects using - * the delegate {@link Comparator}. - * - * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $ - * @since Commons IO 1.4 - */ -class ReverseComparator implements Comparator, Serializable { - - private final Comparator delegate; - - /** - * Construct an instance with the sepecified delegate {@link Comparator}. - * - * @param delegate The comparator to delegate to - */ - public ReverseComparator(Comparator delegate) { - if (delegate == null) { - throw new IllegalArgumentException("Delegate comparator is missing"); - } - this.delegate = delegate; - } - - /** - * Compare using the delegate Comparator, but reversing the result. - * - * @param obj1 The first object to compare - * @param obj2 The second object to compare - * @return the result from the delegate {@link Comparator#compare(Object, Object)} - * reversing the value (i.e. positive becomes negative and vice versa) - */ - public int compare(Object obj1, Object obj2) { - return delegate.compare(obj2, obj1); // parameters switched round - } - -} diff --git a/src/org/apache/commons/io/comparator/SizeFileComparator.java b/src/org/apache/commons/io/comparator/SizeFileComparator.java deleted file mode 100644 index a1621671c..000000000 --- a/src/org/apache/commons/io/comparator/SizeFileComparator.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.comparator; - -import java.io.File; -import java.io.Serializable; -import java.util.Comparator; - -import org.apache.commons.io.FileUtils; - -/** - * Compare the length/size of two files for order (see - * {@link File#length()} and {@link FileUtils#sizeOfDirectory(File)}). - *

- * This comparator can be used to sort lists or arrays of files - * by their length/size. - *

- * Example of sorting a list of files using the - * {@link #SIZE_COMPARATOR} singleton instance: - *

- *       List<File> list = ...
- *       Collections.sort(list, LengthFileComparator.LENGTH_COMPARATOR);
- * 
- *

- * Example of doing a reverse sort of an array of files using the - * {@link #SIZE_REVERSE} singleton instance: - *

- *       File[] array = ...
- *       Arrays.sort(array, LengthFileComparator.LENGTH_REVERSE);
- * 
- *

- * N.B. Directories are treated as zero size unless - * sumDirectoryContents is true. - * - * @version $Revision: 609243 $ $Date: 2008-01-06 00:30:42 +0000 (Sun, 06 Jan 2008) $ - * @since Commons IO 1.4 - */ -public class SizeFileComparator implements Comparator, Serializable { - - /** Size comparator instance - directories are treated as zero size */ - public static final Comparator SIZE_COMPARATOR = new SizeFileComparator(); - - /** Reverse size comparator instance - directories are treated as zero size */ - public static final Comparator SIZE_REVERSE = new ReverseComparator(SIZE_COMPARATOR); - - /** - * Size comparator instance which sums the size of a directory's contents - * using {@link FileUtils#sizeOfDirectory(File)} - */ - public static final Comparator SIZE_SUMDIR_COMPARATOR = new SizeFileComparator(true); - - /** - * Reverse size comparator instance which sums the size of a directory's contents - * using {@link FileUtils#sizeOfDirectory(File)} - */ - public static final Comparator SIZE_SUMDIR_REVERSE = new ReverseComparator(SIZE_SUMDIR_COMPARATOR); - - /** Whether the sum of the directory's contents should be calculated. */ - private final boolean sumDirectoryContents; - - /** - * Construct a file size comparator instance (directories treated as zero size). - */ - public SizeFileComparator() { - this.sumDirectoryContents = false; - } - - /** - * Construct a file size comparator instance specifying whether the size of - * the directory contents should be aggregated. - *

- * If the sumDirectoryContents is true The size of - * directories is calculated using {@link FileUtils#sizeOfDirectory(File)}. - * - * @param sumDirectoryContents true if the sum of the directoryies contents - * should be calculated, otherwise false if directories should be treated - * as size zero (see {@link FileUtils#sizeOfDirectory(File)}). - */ - public SizeFileComparator(boolean sumDirectoryContents) { - this.sumDirectoryContents = sumDirectoryContents; - } - - /** - * Compare the length of two files. - * - * @param obj1 The first file to compare - * @param obj2 The second file to compare - * @return a negative value if the first file's length - * is less than the second, zero if the lengths are the - * same and a positive value if the first files length - * is greater than the second file. - * - */ - public int compare(Object obj1, Object obj2) { - File file1 = (File)obj1; - File file2 = (File)obj2; - long size1 = 0; - if (file1.isDirectory()) { - size1 = sumDirectoryContents && file1.exists() ? FileUtils.sizeOfDirectory(file1) : 0; - } else { - size1 = file1.length(); - } - long size2 = 0; - if (file2.isDirectory()) { - size2 = sumDirectoryContents && file2.exists() ? FileUtils.sizeOfDirectory(file2) : 0; - } else { - size2 = file2.length(); - } - long result = size1 - size2; - if (result < 0) { - return -1; - } else if (result > 0) { - return 1; - } else { - return 0; - } - } -} diff --git a/src/org/apache/commons/io/comparator/package.html b/src/org/apache/commons/io/comparator/package.html deleted file mode 100644 index a2f756f18..000000000 --- a/src/org/apache/commons/io/comparator/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - -

This package provides various {@link java.util.Comparator} implementations -for {@link java.io.File}s. -

- - - diff --git a/src/org/apache/commons/io/filefilter/AbstractFileFilter.java b/src/org/apache/commons/io/filefilter/AbstractFileFilter.java deleted file mode 100644 index 9e188f82e..000000000 --- a/src/org/apache/commons/io/filefilter/AbstractFileFilter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; - -/** - * An abstract class which implements the Java FileFilter and FilenameFilter - * interfaces via the IOFileFilter interface. - *

- * Note that a subclass must override one of the accept methods, - * otherwise your class will infinitely loop. - * - * @since Commons IO 1.0 - * @version $Revision: 539231 $ $Date: 2007-05-18 04:10:33 +0100 (Fri, 18 May 2007) $ - * - * @author Stephen Colebourne - */ -public abstract class AbstractFileFilter implements IOFileFilter { - - /** - * Checks to see if the File should be accepted by this filter. - * - * @param file the File to check - * @return true if this file matches the test - */ - public boolean accept(File file) { - return accept(file.getParentFile(), file.getName()); - } - - /** - * Checks to see if the File should be accepted by this filter. - * - * @param dir the directory File to check - * @param name the filename within the directory to check - * @return true if this file matches the test - */ - public boolean accept(File dir, String name) { - return accept(new File(dir, name)); - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - String name = getClass().getName(); - int period = name.lastIndexOf('.'); - return (period > 0 ? name.substring(period + 1) : name); - } - -} diff --git a/src/org/apache/commons/io/filefilter/AgeFileFilter.java b/src/org/apache/commons/io/filefilter/AgeFileFilter.java deleted file mode 100644 index ab73cb840..000000000 --- a/src/org/apache/commons/io/filefilter/AgeFileFilter.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.Date; - -import org.apache.commons.io.FileUtils; - -/** - * Filters files based on a cutoff time, can filter either newer - * files or files equal to or older. - *

- * For example, to print all files and directories in the - * current directory older than one day: - * - *

- * File dir = new File(".");
- * // We are interested in files older than one day
- * long cutoff = System.currentTimeMillis() - (24 * 60 * 60 * 1000);
- * String[] files = dir.list( new AgeFileFilter(cutoff) );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @author Rahul Akolkar - * @version $Id: AgeFileFilter.java 606381 2007-12-22 02:03:16Z ggregory $ - * @since Commons IO 1.2 - */ -public class AgeFileFilter extends AbstractFileFilter implements Serializable { - - /** The cutoff time threshold. */ - private final long cutoff; - /** Whether the files accepted will be older or newer. */ - private final boolean acceptOlder; - - /** - * Constructs a new age file filter for files equal to or older than - * a certain cutoff - * - * @param cutoff the threshold age of the files - */ - public AgeFileFilter(long cutoff) { - this(cutoff, true); - } - - /** - * Constructs a new age file filter for files on any one side - * of a certain cutoff. - * - * @param cutoff the threshold age of the files - * @param acceptOlder if true, older files (at or before the cutoff) - * are accepted, else newer ones (after the cutoff). - */ - public AgeFileFilter(long cutoff, boolean acceptOlder) { - this.acceptOlder = acceptOlder; - this.cutoff = cutoff; - } - - /** - * Constructs a new age file filter for files older than (at or before) - * a certain cutoff date. - * - * @param cutoffDate the threshold age of the files - */ - public AgeFileFilter(Date cutoffDate) { - this(cutoffDate, true); - } - - /** - * Constructs a new age file filter for files on any one side - * of a certain cutoff date. - * - * @param cutoffDate the threshold age of the files - * @param acceptOlder if true, older files (at or before the cutoff) - * are accepted, else newer ones (after the cutoff). - */ - public AgeFileFilter(Date cutoffDate, boolean acceptOlder) { - this(cutoffDate.getTime(), acceptOlder); - } - - /** - * Constructs a new age file filter for files older than (at or before) - * a certain File (whose last modification time will be used as reference). - * - * @param cutoffReference the file whose last modification - * time is usesd as the threshold age of the files - */ - public AgeFileFilter(File cutoffReference) { - this(cutoffReference, true); - } - - /** - * Constructs a new age file filter for files on any one side - * of a certain File (whose last modification time will be used as - * reference). - * - * @param cutoffReference the file whose last modification - * time is usesd as the threshold age of the files - * @param acceptOlder if true, older files (at or before the cutoff) - * are accepted, else newer ones (after the cutoff). - */ - public AgeFileFilter(File cutoffReference, boolean acceptOlder) { - this(cutoffReference.lastModified(), acceptOlder); - } - - //----------------------------------------------------------------------- - /** - * Checks to see if the last modification of the file matches cutoff - * favorably. - *

- * If last modification time equals cutoff and newer files are required, - * file IS NOT selected. - * If last modification time equals cutoff and older files are required, - * file IS selected. - * - * @param file the File to check - * @return true if the filename matches - */ - public boolean accept(File file) { - boolean newer = FileUtils.isFileNewer(file, cutoff); - return acceptOlder ? !newer : newer; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - String condition = acceptOlder ? "<=" : ">"; - return super.toString() + "(" + condition + cutoff + ")"; - } -} diff --git a/src/org/apache/commons/io/filefilter/AndFileFilter.java b/src/org/apache/commons/io/filefilter/AndFileFilter.java deleted file mode 100644 index deda11f93..000000000 --- a/src/org/apache/commons/io/filefilter/AndFileFilter.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * A {@link java.io.FileFilter} providing conditional AND logic across a list of - * file filters. This filter returns true if all filters in the - * list return true. Otherwise, it returns false. - * Checking of the file filter list stops when the first filter returns - * false. - * - * @since Commons IO 1.0 - * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $ - * - * @author Steven Caswell - */ -public class AndFileFilter - extends AbstractFileFilter - implements ConditionalFileFilter, Serializable { - - /** The list of file filters. */ - private List fileFilters; - - /** - * Constructs a new instance of AndFileFilter. - * - * @since Commons IO 1.1 - */ - public AndFileFilter() { - this.fileFilters = new ArrayList(); - } - - /** - * Constructs a new instance of AndFileFilter - * with the specified list of filters. - * - * @param fileFilters a List of IOFileFilter instances, copied, null ignored - * @since Commons IO 1.1 - */ - public AndFileFilter(final List fileFilters) { - if (fileFilters == null) { - this.fileFilters = new ArrayList(); - } else { - this.fileFilters = new ArrayList(fileFilters); - } - } - - /** - * Constructs a new file filter that ANDs the result of two other filters. - * - * @param filter1 the first filter, must not be null - * @param filter2 the second filter, must not be null - * @throws IllegalArgumentException if either filter is null - */ - public AndFileFilter(IOFileFilter filter1, IOFileFilter filter2) { - if (filter1 == null || filter2 == null) { - throw new IllegalArgumentException("The filters must not be null"); - } - this.fileFilters = new ArrayList(); - addFileFilter(filter1); - addFileFilter(filter2); - } - - /** - * {@inheritDoc} - */ - public void addFileFilter(final IOFileFilter ioFileFilter) { - this.fileFilters.add(ioFileFilter); - } - - /** - * {@inheritDoc} - */ - public List getFileFilters() { - return Collections.unmodifiableList(this.fileFilters); - } - - /** - * {@inheritDoc} - */ - public boolean removeFileFilter(final IOFileFilter ioFileFilter) { - return this.fileFilters.remove(ioFileFilter); - } - - /** - * {@inheritDoc} - */ - public void setFileFilters(final List fileFilters) { - this.fileFilters = new ArrayList(fileFilters); - } - - /** - * {@inheritDoc} - */ - public boolean accept(final File file) { - if (this.fileFilters.size() == 0) { - return false; - } - for (Iterator iter = this.fileFilters.iterator(); iter.hasNext();) { - IOFileFilter fileFilter = (IOFileFilter) iter.next(); - if (!fileFilter.accept(file)) { - return false; - } - } - return true; - } - - /** - * {@inheritDoc} - */ - public boolean accept(final File file, final String name) { - if (this.fileFilters.size() == 0) { - return false; - } - for (Iterator iter = this.fileFilters.iterator(); iter.hasNext();) { - IOFileFilter fileFilter = (IOFileFilter) iter.next(); - if (!fileFilter.accept(file, name)) { - return false; - } - } - return true; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(super.toString()); - buffer.append("("); - if (fileFilters != null) { - for (int i = 0; i < fileFilters.size(); i++) { - if (i > 0) { - buffer.append(","); - } - Object filter = fileFilters.get(i); - buffer.append(filter == null ? "null" : filter.toString()); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/CanReadFileFilter.java b/src/org/apache/commons/io/filefilter/CanReadFileFilter.java deleted file mode 100644 index a9c132570..000000000 --- a/src/org/apache/commons/io/filefilter/CanReadFileFilter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * This filter accepts Files that can be read. - *

- * Example, showing how to print out a list of the - * current directory's readable files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( CanReadFileFilter.CAN_READ );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the - * current directory's un-readable files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( CanReadFileFilter.CANNOT_READ );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the - * current directory's read-only files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( CanReadFileFilter.READ_ONLY );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.3 - * @version $Revision: 587916 $ - */ -public class CanReadFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of readable filter */ - public static final IOFileFilter CAN_READ = new CanReadFileFilter(); - - /** Singleton instance of not readable filter */ - public static final IOFileFilter CANNOT_READ = new NotFileFilter(CAN_READ); - - /** Singleton instance of read-only filter */ - public static final IOFileFilter READ_ONLY = new AndFileFilter(CAN_READ, - CanWriteFileFilter.CANNOT_WRITE); - - /** - * Restrictive consructor. - */ - protected CanReadFileFilter() { - } - - /** - * Checks to see if the file can be read. - * - * @param file the File to check. - * @return true if the file can be - * read, otherwise false. - */ - public boolean accept(File file) { - return file.canRead(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java b/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java deleted file mode 100644 index da664f25c..000000000 --- a/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * This filter accepts Files that can be written to. - *

- * Example, showing how to print out a list of the - * current directory's writable files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( CanWriteFileFilter.CAN_WRITE );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the - * current directory's un-writable files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( CanWriteFileFilter.CANNOT_WRITE );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - *

- * N.B. For read-only files, use - * CanReadFileFilter.READ_ONLY. - * - * @since Commons IO 1.3 - * @version $Revision: 587916 $ - */ -public class CanWriteFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of writable filter */ - public static final IOFileFilter CAN_WRITE = new CanWriteFileFilter(); - - /** Singleton instance of not writable filter */ - public static final IOFileFilter CANNOT_WRITE = new NotFileFilter(CAN_WRITE); - - /** - * Restrictive consructor. - */ - protected CanWriteFileFilter() { - } - - /** - * Checks to see if the file can be written to. - * - * @param file the File to check - * @return true if the file can be - * written to, otherwise false. - */ - public boolean accept(File file) { - return file.canWrite(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java b/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java deleted file mode 100644 index ce1419ee8..000000000 --- a/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.util.List; - -/** - * Defines operations for conditional file filters. - * - * @since Commons IO 1.1 - * @version $Revision: 437567 $ $Date: 2006-08-28 07:39:07 +0100 (Mon, 28 Aug 2006) $ - * - * @author Steven Caswell - */ -public interface ConditionalFileFilter { - - /** - * Adds the specified file filter to the list of file filters at the end of - * the list. - * - * @param ioFileFilter the filter to be added - * @since Commons IO 1.1 - */ - public void addFileFilter(IOFileFilter ioFileFilter); - - /** - * Returns this conditional file filter's list of file filters. - * - * @return the file filter list - * @since Commons IO 1.1 - */ - public List getFileFilters(); - - /** - * Removes the specified file filter. - * - * @param ioFileFilter filter to be removed - * @return true if the filter was found in the list, - * false otherwise - * @since Commons IO 1.1 - */ - public boolean removeFileFilter(IOFileFilter ioFileFilter); - - /** - * Sets the list of file filters, replacing any previously configured - * file filters on this filter. - * - * @param fileFilters the list of filters - * @since Commons IO 1.1 - */ - public void setFileFilters(List fileFilters); - -} diff --git a/src/org/apache/commons/io/filefilter/DelegateFileFilter.java b/src/org/apache/commons/io/filefilter/DelegateFileFilter.java deleted file mode 100644 index c2d67c469..000000000 --- a/src/org/apache/commons/io/filefilter/DelegateFileFilter.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.io.Serializable; - -/** - * This class turns a Java FileFilter or FilenameFilter into an IO FileFilter. - * - * @since Commons IO 1.0 - * @version $Revision: 591058 $ $Date: 2007-11-01 15:47:05 +0000 (Thu, 01 Nov 2007) $ - * - * @author Stephen Colebourne - */ -public class DelegateFileFilter extends AbstractFileFilter implements Serializable { - - /** The Filename filter */ - private final FilenameFilter filenameFilter; - /** The File filter */ - private final FileFilter fileFilter; - - /** - * Constructs a delegate file filter around an existing FilenameFilter. - * - * @param filter the filter to decorate - */ - public DelegateFileFilter(FilenameFilter filter) { - if (filter == null) { - throw new IllegalArgumentException("The FilenameFilter must not be null"); - } - this.filenameFilter = filter; - this.fileFilter = null; - } - - /** - * Constructs a delegate file filter around an existing FileFilter. - * - * @param filter the filter to decorate - */ - public DelegateFileFilter(FileFilter filter) { - if (filter == null) { - throw new IllegalArgumentException("The FileFilter must not be null"); - } - this.fileFilter = filter; - this.filenameFilter = null; - } - - /** - * Checks the filter. - * - * @param file the file to check - * @return true if the filter matches - */ - public boolean accept(File file) { - if (fileFilter != null) { - return fileFilter.accept(file); - } else { - return super.accept(file); - } - } - - /** - * Checks the filter. - * - * @param dir the directory - * @param name the filename in the directory - * @return true if the filter matches - */ - public boolean accept(File dir, String name) { - if (filenameFilter != null) { - return filenameFilter.accept(dir, name); - } else { - return super.accept(dir, name); - } - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - String delegate = (fileFilter != null ? fileFilter.toString() : filenameFilter.toString()); - return super.toString() + "(" + delegate + ")"; - } - -} diff --git a/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java b/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java deleted file mode 100644 index 3412e7bef..000000000 --- a/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * This filter accepts Files that are directories. - *

- * For example, here is how to print out a list of the - * current directory's subdirectories: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( DirectoryFileFilter.INSTANCE );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.0 - * @version $Revision: 587916 $ $Date: 2007-10-24 16:53:07 +0100 (Wed, 24 Oct 2007) $ - * - * @author Stephen Colebourne - * @author Peter Donald - */ -public class DirectoryFileFilter extends AbstractFileFilter implements Serializable { - - /** - * Singleton instance of directory filter. - * @since Commons IO 1.3 - */ - public static final IOFileFilter DIRECTORY = new DirectoryFileFilter(); - /** - * Singleton instance of directory filter. - * Please use the identical DirectoryFileFilter.DIRECTORY constant. - * The new name is more JDK 1.5 friendly as it doesn't clash with other - * values when using static imports. - */ - public static final IOFileFilter INSTANCE = DIRECTORY; - - /** - * Restrictive consructor. - */ - protected DirectoryFileFilter() { - } - - /** - * Checks to see if the file is a directory. - * - * @param file the File to check - * @return true if the file is a directory - */ - public boolean accept(File file) { - return file.isDirectory(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/EmptyFileFilter.java b/src/org/apache/commons/io/filefilter/EmptyFileFilter.java deleted file mode 100644 index e88a862d4..000000000 --- a/src/org/apache/commons/io/filefilter/EmptyFileFilter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * This filter accepts files or directories that are empty. - *

- * If the File is a directory it checks that - * it contains no files. - *

- * Example, showing how to print out a list of the - * current directory's empty files/directories: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( EmptyFileFilter.EMPTY );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the - * current directory's non-empty files/directories: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( EmptyFileFilter.NOT_EMPTY );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.3 - * @version $Revision: 587916 $ - */ -public class EmptyFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of empty filter */ - public static final IOFileFilter EMPTY = new EmptyFileFilter(); - - /** Singleton instance of not-empty filter */ - public static final IOFileFilter NOT_EMPTY = new NotFileFilter(EMPTY); - - /** - * Restrictive consructor. - */ - protected EmptyFileFilter() { - } - - /** - * Checks to see if the file is empty. - * - * @param file the file or directory to check - * @return true if the file or directory - * is empty, otherwise false. - */ - public boolean accept(File file) { - if (file.isDirectory()) { - File[] files = file.listFiles(); - return (files == null || files.length == 0); - } else { - return (file.length() == 0); - } - } - -} diff --git a/src/org/apache/commons/io/filefilter/FalseFileFilter.java b/src/org/apache/commons/io/filefilter/FalseFileFilter.java deleted file mode 100644 index 8a87d4092..000000000 --- a/src/org/apache/commons/io/filefilter/FalseFileFilter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * A file filter that always returns false. - * - * @since Commons IO 1.0 - * @version $Revision: 587978 $ $Date: 2007-10-24 20:36:51 +0100 (Wed, 24 Oct 2007) $ - * - * @author Stephen Colebourne - */ -public class FalseFileFilter implements IOFileFilter, Serializable { - - /** - * Singleton instance of false filter. - * @since Commons IO 1.3 - */ - public static final IOFileFilter FALSE = new FalseFileFilter(); - /** - * Singleton instance of false filter. - * Please use the identical FalseFileFilter.FALSE constant. - * The new name is more JDK 1.5 friendly as it doesn't clash with other - * values when using static imports. - */ - public static final IOFileFilter INSTANCE = FALSE; - - /** - * Restrictive consructor. - */ - protected FalseFileFilter() { - } - - /** - * Returns false. - * - * @param file the file to check - * @return false - */ - public boolean accept(File file) { - return false; - } - - /** - * Returns false. - * - * @param dir the directory to check - * @param name the filename - * @return false - */ - public boolean accept(File dir, String name) { - return false; - } - -} diff --git a/src/org/apache/commons/io/filefilter/FileFileFilter.java b/src/org/apache/commons/io/filefilter/FileFileFilter.java deleted file mode 100644 index 0d49eddd4..000000000 --- a/src/org/apache/commons/io/filefilter/FileFileFilter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * This filter accepts Files that are files (not directories). - *

- * For example, here is how to print out a list of the real files - * within the current directory: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( FileFileFilter.FILE );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.3 - * @version $Revision: 155419 $ $Date: 2007-10-24 16:53:07 +0100 (Wed, 24 Oct 2007) $ - */ -public class FileFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of file filter */ - public static final IOFileFilter FILE = new FileFileFilter(); - - /** - * Restrictive consructor. - */ - protected FileFileFilter() { - } - - /** - * Checks to see if the file is a file. - * - * @param file the File to check - * @return true if the file is a file - */ - public boolean accept(File file) { - return file.isFile(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/FileFilterUtils.java b/src/org/apache/commons/io/filefilter/FileFilterUtils.java deleted file mode 100644 index 71c37b1d2..000000000 --- a/src/org/apache/commons/io/filefilter/FileFilterUtils.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.util.Date; - -/** - * Useful utilities for working with file filters. It provides access to all - * file filter implementations in this package so you don't have to import - * every class you use. - * - * @since Commons IO 1.0 - * @version $Id: FileFilterUtils.java 609286 2008-01-06 10:01:26Z scolebourne $ - * - * @author Stephen Colebourne - * @author Jeremias Maerki - * @author Masato Tezuka - * @author Rahul Akolkar - */ -public class FileFilterUtils { - - /** - * FileFilterUtils is not normally instantiated. - */ - public FileFilterUtils() { - } - - //----------------------------------------------------------------------- - /** - * Returns a filter that returns true if the filename starts with the specified text. - * - * @param prefix the filename prefix - * @return a prefix checking filter - */ - public static IOFileFilter prefixFileFilter(String prefix) { - return new PrefixFileFilter(prefix); - } - - /** - * Returns a filter that returns true if the filename ends with the specified text. - * - * @param suffix the filename suffix - * @return a suffix checking filter - */ - public static IOFileFilter suffixFileFilter(String suffix) { - return new SuffixFileFilter(suffix); - } - - /** - * Returns a filter that returns true if the filename matches the specified text. - * - * @param name the filename - * @return a name checking filter - */ - public static IOFileFilter nameFileFilter(String name) { - return new NameFileFilter(name); - } - - /** - * Returns a filter that checks if the file is a directory. - * - * @return file filter that accepts only directories and not files - */ - public static IOFileFilter directoryFileFilter() { - return DirectoryFileFilter.DIRECTORY; - } - - /** - * Returns a filter that checks if the file is a file (and not a directory). - * - * @return file filter that accepts only files and not directories - */ - public static IOFileFilter fileFileFilter() { - return FileFileFilter.FILE; - } - - //----------------------------------------------------------------------- - /** - * Returns a filter that ANDs the two specified filters. - * - * @param filter1 the first filter - * @param filter2 the second filter - * @return a filter that ANDs the two specified filters - */ - public static IOFileFilter andFileFilter(IOFileFilter filter1, IOFileFilter filter2) { - return new AndFileFilter(filter1, filter2); - } - - /** - * Returns a filter that ORs the two specified filters. - * - * @param filter1 the first filter - * @param filter2 the second filter - * @return a filter that ORs the two specified filters - */ - public static IOFileFilter orFileFilter(IOFileFilter filter1, IOFileFilter filter2) { - return new OrFileFilter(filter1, filter2); - } - - /** - * Returns a filter that NOTs the specified filter. - * - * @param filter the filter to invert - * @return a filter that NOTs the specified filter - */ - public static IOFileFilter notFileFilter(IOFileFilter filter) { - return new NotFileFilter(filter); - } - - //----------------------------------------------------------------------- - /** - * Returns a filter that always returns true. - * - * @return a true filter - */ - public static IOFileFilter trueFileFilter() { - return TrueFileFilter.TRUE; - } - - /** - * Returns a filter that always returns false. - * - * @return a false filter - */ - public static IOFileFilter falseFileFilter() { - return FalseFileFilter.FALSE; - } - - //----------------------------------------------------------------------- - /** - * Returns an IOFileFilter that wraps the - * FileFilter instance. - * - * @param filter the filter to be wrapped - * @return a new filter that implements IOFileFilter - */ - public static IOFileFilter asFileFilter(FileFilter filter) { - return new DelegateFileFilter(filter); - } - - /** - * Returns an IOFileFilter that wraps the - * FilenameFilter instance. - * - * @param filter the filter to be wrapped - * @return a new filter that implements IOFileFilter - */ - public static IOFileFilter asFileFilter(FilenameFilter filter) { - return new DelegateFileFilter(filter); - } - - //----------------------------------------------------------------------- - /** - * Returns a filter that returns true if the file was last modified after - * the specified cutoff time. - * - * @param cutoff the time threshold - * @return an appropriately configured age file filter - * @since Commons IO 1.2 - */ - public static IOFileFilter ageFileFilter(long cutoff) { - return new AgeFileFilter(cutoff); - } - - /** - * Returns a filter that filters files based on a cutoff time. - * - * @param cutoff the time threshold - * @param acceptOlder if true, older files get accepted, if false, newer - * @return an appropriately configured age file filter - * @since Commons IO 1.2 - */ - public static IOFileFilter ageFileFilter(long cutoff, boolean acceptOlder) { - return new AgeFileFilter(cutoff, acceptOlder); - } - - /** - * Returns a filter that returns true if the file was last modified after - * the specified cutoff date. - * - * @param cutoffDate the time threshold - * @return an appropriately configured age file filter - * @since Commons IO 1.2 - */ - public static IOFileFilter ageFileFilter(Date cutoffDate) { - return new AgeFileFilter(cutoffDate); - } - - /** - * Returns a filter that filters files based on a cutoff date. - * - * @param cutoffDate the time threshold - * @param acceptOlder if true, older files get accepted, if false, newer - * @return an appropriately configured age file filter - * @since Commons IO 1.2 - */ - public static IOFileFilter ageFileFilter(Date cutoffDate, boolean acceptOlder) { - return new AgeFileFilter(cutoffDate, acceptOlder); - } - - /** - * Returns a filter that returns true if the file was last modified after - * the specified reference file. - * - * @param cutoffReference the file whose last modification - * time is usesd as the threshold age of the files - * @return an appropriately configured age file filter - * @since Commons IO 1.2 - */ - public static IOFileFilter ageFileFilter(File cutoffReference) { - return new AgeFileFilter(cutoffReference); - } - - /** - * Returns a filter that filters files based on a cutoff reference file. - * - * @param cutoffReference the file whose last modification - * time is usesd as the threshold age of the files - * @param acceptOlder if true, older files get accepted, if false, newer - * @return an appropriately configured age file filter - * @since Commons IO 1.2 - */ - public static IOFileFilter ageFileFilter(File cutoffReference, boolean acceptOlder) { - return new AgeFileFilter(cutoffReference, acceptOlder); - } - - //----------------------------------------------------------------------- - /** - * Returns a filter that returns true if the file is bigger than a certain size. - * - * @param threshold the file size threshold - * @return an appropriately configured SizeFileFilter - * @since Commons IO 1.2 - */ - public static IOFileFilter sizeFileFilter(long threshold) { - return new SizeFileFilter(threshold); - } - - /** - * Returns a filter that filters based on file size. - * - * @param threshold the file size threshold - * @param acceptLarger if true, larger files get accepted, if false, smaller - * @return an appropriately configured SizeFileFilter - * @since Commons IO 1.2 - */ - public static IOFileFilter sizeFileFilter(long threshold, boolean acceptLarger) { - return new SizeFileFilter(threshold, acceptLarger); - } - - /** - * Returns a filter that accepts files whose size is >= minimum size - * and <= maximum size. - * - * @param minSizeInclusive the minimum file size (inclusive) - * @param maxSizeInclusive the maximum file size (inclusive) - * @return an appropriately configured IOFileFilter - * @since Commons IO 1.3 - */ - public static IOFileFilter sizeRangeFileFilter(long minSizeInclusive, long maxSizeInclusive ) { - IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true); - IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false); - return new AndFileFilter(minimumFilter, maximumFilter); - } - - //----------------------------------------------------------------------- - /* Constructed on demand and then cached */ - private static IOFileFilter cvsFilter; - - /* Constructed on demand and then cached */ - private static IOFileFilter svnFilter; - - /** - * Decorates a filter to make it ignore CVS directories. - * Passing in null will return a filter that accepts everything - * except CVS directories. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @since Commons IO 1.1 (method existed but had bug in 1.0) - */ - public static IOFileFilter makeCVSAware(IOFileFilter filter) { - if (cvsFilter == null) { - cvsFilter = notFileFilter( - andFileFilter(directoryFileFilter(), nameFileFilter("CVS"))); - } - if (filter == null) { - return cvsFilter; - } else { - return andFileFilter(filter, cvsFilter); - } - } - - /** - * Decorates a filter to make it ignore SVN directories. - * Passing in null will return a filter that accepts everything - * except SVN directories. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @since Commons IO 1.1 - */ - public static IOFileFilter makeSVNAware(IOFileFilter filter) { - if (svnFilter == null) { - svnFilter = notFileFilter( - andFileFilter(directoryFileFilter(), nameFileFilter(".svn"))); - } - if (filter == null) { - return svnFilter; - } else { - return andFileFilter(filter, svnFilter); - } - } - - //----------------------------------------------------------------------- - /** - * Decorates a filter so that it only applies to directories and not to files. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @since Commons IO 1.3 - */ - public static IOFileFilter makeDirectoryOnly(IOFileFilter filter) { - if (filter == null) { - return DirectoryFileFilter.DIRECTORY; - } - return new AndFileFilter(DirectoryFileFilter.DIRECTORY, filter); - } - - /** - * Decorates a filter so that it only applies to files and not to directories. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @since Commons IO 1.3 - */ - public static IOFileFilter makeFileOnly(IOFileFilter filter) { - if (filter == null) { - return FileFileFilter.FILE; - } - return new AndFileFilter(FileFileFilter.FILE, filter); - } - -} diff --git a/src/org/apache/commons/io/filefilter/HiddenFileFilter.java b/src/org/apache/commons/io/filefilter/HiddenFileFilter.java deleted file mode 100644 index 244153d5e..000000000 --- a/src/org/apache/commons/io/filefilter/HiddenFileFilter.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * This filter accepts Files that are hidden. - *

- * Example, showing how to print out a list of the - * current directory's hidden files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( HiddenFileFilter.HIDDEN );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the - * current directory's visible (i.e. not hidden) files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( HiddenFileFilter.VISIBLE );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.3 - * @version $Revision: 587916 $ - */ -public class HiddenFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of hidden filter */ - public static final IOFileFilter HIDDEN = new HiddenFileFilter(); - - /** Singleton instance of visible filter */ - public static final IOFileFilter VISIBLE = new NotFileFilter(HIDDEN); - - /** - * Restrictive consructor. - */ - protected HiddenFileFilter() { - } - - /** - * Checks to see if the file is hidden. - * - * @param file the File to check - * @return true if the file is - * hidden, otherwise false. - */ - public boolean accept(File file) { - return file.isHidden(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/IOFileFilter.java b/src/org/apache/commons/io/filefilter/IOFileFilter.java deleted file mode 100644 index 5ebd82751..000000000 --- a/src/org/apache/commons/io/filefilter/IOFileFilter.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; - -/** - * An interface which brings the FileFilter and FilenameFilter - * interfaces together. - * - * @since Commons IO 1.0 - * @version $Revision: 471628 $ $Date: 2006-11-06 04:06:45 +0000 (Mon, 06 Nov 2006) $ - * - * @author Stephen Colebourne - */ -public interface IOFileFilter extends FileFilter, FilenameFilter { - - /** - * Checks to see if the File should be accepted by this filter. - *

- * Defined in {@link java.io.FileFilter}. - * - * @param file the File to check - * @return true if this file matches the test - */ - public boolean accept(File file); - - /** - * Checks to see if the File should be accepted by this filter. - *

- * Defined in {@link java.io.FilenameFilter}. - * - * @param dir the directory File to check - * @param name the filename within the directory to check - * @return true if this file matches the test - */ - public boolean accept(File dir, String name); - -} diff --git a/src/org/apache/commons/io/filefilter/NameFileFilter.java b/src/org/apache/commons/io/filefilter/NameFileFilter.java deleted file mode 100644 index fa1c80f73..000000000 --- a/src/org/apache/commons/io/filefilter/NameFileFilter.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.List; - -import org.apache.commons.io.IOCase; - -/** - * Filters filenames for a certain name. - *

- * For example, to print all files and directories in the - * current directory whose name is Test: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( new NameFileFilter("Test") );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.0 - * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $ - * - * @author Stephen Colebourne - * @author Federico Barbieri - * @author Serge Knystautas - * @author Peter Donald - */ -public class NameFileFilter extends AbstractFileFilter implements Serializable { - - /** The filenames to search for */ - private final String[] names; - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Constructs a new case-sensitive name file filter for a single name. - * - * @param name the name to allow, must not be null - * @throws IllegalArgumentException if the name is null - */ - public NameFileFilter(String name) { - this(name, null); - } - - /** - * Construct a new name file filter specifying case-sensitivity. - * - * @param name the name to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the name is null - */ - public NameFileFilter(String name, IOCase caseSensitivity) { - if (name == null) { - throw new IllegalArgumentException("The wildcard must not be null"); - } - this.names = new String[] {name}; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Constructs a new case-sensitive name file filter for an array of names. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param names the names to allow, must not be null - * @throws IllegalArgumentException if the names array is null - */ - public NameFileFilter(String[] names) { - this(names, null); - } - - /** - * Constructs a new name file filter for an array of names specifying case-sensitivity. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param names the names to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the names array is null - */ - public NameFileFilter(String[] names, IOCase caseSensitivity) { - if (names == null) { - throw new IllegalArgumentException("The array of names must not be null"); - } - this.names = names; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Constructs a new case-sensitive name file filter for a list of names. - * - * @param names the names to allow, must not be null - * @throws IllegalArgumentException if the name list is null - * @throws ClassCastException if the list does not contain Strings - */ - public NameFileFilter(List names) { - this(names, null); - } - - /** - * Constructs a new name file filter for a list of names specifying case-sensitivity. - * - * @param names the names to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the name list is null - * @throws ClassCastException if the list does not contain Strings - */ - public NameFileFilter(List names, IOCase caseSensitivity) { - if (names == null) { - throw new IllegalArgumentException("The list of names must not be null"); - } - this.names = (String[]) names.toArray(new String[names.size()]); - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - //----------------------------------------------------------------------- - /** - * Checks to see if the filename matches. - * - * @param file the File to check - * @return true if the filename matches - */ - public boolean accept(File file) { - String name = file.getName(); - for (int i = 0; i < this.names.length; i++) { - if (caseSensitivity.checkEquals(name, names[i])) { - return true; - } - } - return false; - } - - /** - * Checks to see if the filename matches. - * - * @param file the File directory - * @param name the filename - * @return true if the filename matches - */ - public boolean accept(File file, String name) { - for (int i = 0; i < names.length; i++) { - if (caseSensitivity.checkEquals(name, names[i])) { - return true; - } - } - return false; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(super.toString()); - buffer.append("("); - if (names != null) { - for (int i = 0; i < names.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(names[i]); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/NotFileFilter.java b/src/org/apache/commons/io/filefilter/NotFileFilter.java deleted file mode 100644 index 710c8ecf3..000000000 --- a/src/org/apache/commons/io/filefilter/NotFileFilter.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * This filter produces a logical NOT of the filters specified. - * - * @since Commons IO 1.0 - * @version $Revision: 591058 $ $Date: 2007-11-01 15:47:05 +0000 (Thu, 01 Nov 2007) $ - * - * @author Stephen Colebourne - */ -public class NotFileFilter extends AbstractFileFilter implements Serializable { - - /** The filter */ - private final IOFileFilter filter; - - /** - * Constructs a new file filter that NOTs the result of another filters. - * - * @param filter the filter, must not be null - * @throws IllegalArgumentException if the filter is null - */ - public NotFileFilter(IOFileFilter filter) { - if (filter == null) { - throw new IllegalArgumentException("The filter must not be null"); - } - this.filter = filter; - } - - /** - * Checks to see if both filters are true. - * - * @param file the File to check - * @return true if the filter returns false - */ - public boolean accept(File file) { - return ! filter.accept(file); - } - - /** - * Checks to see if both filters are true. - * - * @param file the File directory - * @param name the filename - * @return true if the filter returns false - */ - public boolean accept(File file, String name) { - return ! filter.accept(file, name); - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - return super.toString() + "(" + filter.toString() + ")"; - } - -} diff --git a/src/org/apache/commons/io/filefilter/OrFileFilter.java b/src/org/apache/commons/io/filefilter/OrFileFilter.java deleted file mode 100644 index 59cc0f2b0..000000000 --- a/src/org/apache/commons/io/filefilter/OrFileFilter.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * A {@link java.io.FileFilter} providing conditional OR logic across a list of - * file filters. This filter returns true if any filters in the - * list return true. Otherwise, it returns false. - * Checking of the file filter list stops when the first filter returns - * true. - * - * @since Commons IO 1.0 - * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $ - * - * @author Steven Caswell - */ -public class OrFileFilter - extends AbstractFileFilter - implements ConditionalFileFilter, Serializable { - - /** The list of file filters. */ - private List fileFilters; - - /** - * Constructs a new instance of OrFileFilter. - * - * @since Commons IO 1.1 - */ - public OrFileFilter() { - this.fileFilters = new ArrayList(); - } - - /** - * Constructs a new instance of OrFileFilter - * with the specified filters. - * - * @param fileFilters the file filters for this filter, copied, null ignored - * @since Commons IO 1.1 - */ - public OrFileFilter(final List fileFilters) { - if (fileFilters == null) { - this.fileFilters = new ArrayList(); - } else { - this.fileFilters = new ArrayList(fileFilters); - } - } - - /** - * Constructs a new file filter that ORs the result of two other filters. - * - * @param filter1 the first filter, must not be null - * @param filter2 the second filter, must not be null - * @throws IllegalArgumentException if either filter is null - */ - public OrFileFilter(IOFileFilter filter1, IOFileFilter filter2) { - if (filter1 == null || filter2 == null) { - throw new IllegalArgumentException("The filters must not be null"); - } - this.fileFilters = new ArrayList(); - addFileFilter(filter1); - addFileFilter(filter2); - } - - /** - * {@inheritDoc} - */ - public void addFileFilter(final IOFileFilter ioFileFilter) { - this.fileFilters.add(ioFileFilter); - } - - /** - * {@inheritDoc} - */ - public List getFileFilters() { - return Collections.unmodifiableList(this.fileFilters); - } - - /** - * {@inheritDoc} - */ - public boolean removeFileFilter(IOFileFilter ioFileFilter) { - return this.fileFilters.remove(ioFileFilter); - } - - /** - * {@inheritDoc} - */ - public void setFileFilters(final List fileFilters) { - this.fileFilters = fileFilters; - } - - /** - * {@inheritDoc} - */ - public boolean accept(final File file) { - for (Iterator iter = this.fileFilters.iterator(); iter.hasNext();) { - IOFileFilter fileFilter = (IOFileFilter) iter.next(); - if (fileFilter.accept(file)) { - return true; - } - } - return false; - } - - /** - * {@inheritDoc} - */ - public boolean accept(final File file, final String name) { - for (Iterator iter = this.fileFilters.iterator(); iter.hasNext();) { - IOFileFilter fileFilter = (IOFileFilter) iter.next(); - if (fileFilter.accept(file, name)) { - return true; - } - } - return false; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(super.toString()); - buffer.append("("); - if (fileFilters != null) { - for (int i = 0; i < fileFilters.size(); i++) { - if (i > 0) { - buffer.append(","); - } - Object filter = fileFilters.get(i); - buffer.append(filter == null ? "null" : filter.toString()); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/PrefixFileFilter.java b/src/org/apache/commons/io/filefilter/PrefixFileFilter.java deleted file mode 100644 index 0b6fcb961..000000000 --- a/src/org/apache/commons/io/filefilter/PrefixFileFilter.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.List; - -import org.apache.commons.io.IOCase; - -/** - * Filters filenames for a certain prefix. - *

- * For example, to print all files and directories in the - * current directory whose name starts with Test: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( new PrefixFileFilter("Test") );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.0 - * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $ - * - * @author Stephen Colebourne - * @author Federico Barbieri - * @author Serge Knystautas - * @author Peter Donald - */ -public class PrefixFileFilter extends AbstractFileFilter implements Serializable { - - /** The filename prefixes to search for */ - private final String[] prefixes; - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Constructs a new Prefix file filter for a single prefix. - * - * @param prefix the prefix to allow, must not be null - * @throws IllegalArgumentException if the prefix is null - */ - public PrefixFileFilter(String prefix) { - this(prefix, IOCase.SENSITIVE); - } - - /** - * Constructs a new Prefix file filter for a single prefix - * specifying case-sensitivity. - * - * @param prefix the prefix to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the prefix is null - * @since Commons IO 1.4 - */ - public PrefixFileFilter(String prefix, IOCase caseSensitivity) { - if (prefix == null) { - throw new IllegalArgumentException("The prefix must not be null"); - } - this.prefixes = new String[] {prefix}; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Constructs a new Prefix file filter for any of an array of prefixes. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param prefixes the prefixes to allow, must not be null - * @throws IllegalArgumentException if the prefix array is null - */ - public PrefixFileFilter(String[] prefixes) { - this(prefixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Prefix file filter for any of an array of prefixes - * specifying case-sensitivity. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param prefixes the prefixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the prefix is null - * @since Commons IO 1.4 - */ - public PrefixFileFilter(String[] prefixes, IOCase caseSensitivity) { - if (prefixes == null) { - throw new IllegalArgumentException("The array of prefixes must not be null"); - } - this.prefixes = prefixes; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Constructs a new Prefix file filter for a list of prefixes. - * - * @param prefixes the prefixes to allow, must not be null - * @throws IllegalArgumentException if the prefix list is null - * @throws ClassCastException if the list does not contain Strings - */ - public PrefixFileFilter(List prefixes) { - this(prefixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Prefix file filter for a list of prefixes - * specifying case-sensitivity. - * - * @param prefixes the prefixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the prefix list is null - * @throws ClassCastException if the list does not contain Strings - * @since Commons IO 1.4 - */ - public PrefixFileFilter(List prefixes, IOCase caseSensitivity) { - if (prefixes == null) { - throw new IllegalArgumentException("The list of prefixes must not be null"); - } - this.prefixes = (String[]) prefixes.toArray(new String[prefixes.size()]); - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Checks to see if the filename starts with the prefix. - * - * @param file the File to check - * @return true if the filename starts with one of our prefixes - */ - public boolean accept(File file) { - String name = file.getName(); - for (int i = 0; i < this.prefixes.length; i++) { - if (caseSensitivity.checkStartsWith(name, prefixes[i])) { - return true; - } - } - return false; - } - - /** - * Checks to see if the filename starts with the prefix. - * - * @param file the File directory - * @param name the filename - * @return true if the filename starts with one of our prefixes - */ - public boolean accept(File file, String name) { - for (int i = 0; i < prefixes.length; i++) { - if (caseSensitivity.checkStartsWith(name, prefixes[i])) { - return true; - } - } - return false; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(super.toString()); - buffer.append("("); - if (prefixes != null) { - for (int i = 0; i < prefixes.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(prefixes[i]); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/RegexFileFilter.java b/src/org/apache/commons/io/filefilter/RegexFileFilter.java deleted file mode 100644 index b49a1bd3b..000000000 --- a/src/org/apache/commons/io/filefilter/RegexFileFilter.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.regex.Pattern; - -import org.apache.commons.io.IOCase; - -/** - * Filters files using supplied regular expression(s). - *

- * See java.util.regex.Pattern for regex matching rules - *

- * - *

- * e.g. - *

- * File dir = new File(".");
- * FileFilter fileFilter = new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$");
- * File[] files = dir.listFiles(fileFilter);
- * for (int i = 0; i < files.length; i++) {
- *   System.out.println(files[i]);
- * }
- * 
- * - * @author Oliver Siegmar - * @version $Revision: 606381 $ - * @since Commons IO 1.4 - */ -public class RegexFileFilter extends AbstractFileFilter implements Serializable { - - /** The regular expression pattern that will be used to match filenames */ - private final Pattern pattern; - - /** - * Construct a new regular expression filter. - * - * @param pattern regular string expression to match - * @throws IllegalArgumentException if the pattern is null - */ - public RegexFileFilter(String pattern) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern is missing"); - } - - this.pattern = Pattern.compile(pattern); - } - - /** - * Construct a new regular expression filter with the specified flags case sensitivity. - * - * @param pattern regular string expression to match - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern is null - */ - public RegexFileFilter(String pattern, IOCase caseSensitivity) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern is missing"); - } - int flags = 0; - if (caseSensitivity != null && !caseSensitivity.isCaseSensitive()) { - flags = Pattern.CASE_INSENSITIVE; - } - this.pattern = Pattern.compile(pattern, flags); - } - - /** - * Construct a new regular expression filter with the specified flags. - * - * @param pattern regular string expression to match - * @param flags pattern flags - e.g. {@link Pattern#CASE_INSENSITIVE} - * @throws IllegalArgumentException if the pattern is null - */ - public RegexFileFilter(String pattern, int flags) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern is missing"); - } - this.pattern = Pattern.compile(pattern, flags); - } - - /** - * Construct a new regular expression filter for a compiled regular expression - * - * @param pattern regular expression to match - * @throws IllegalArgumentException if the pattern is null - */ - public RegexFileFilter(Pattern pattern) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern is missing"); - } - - this.pattern = pattern; - } - - /** - * Checks to see if the filename matches one of the regular expressions. - * - * @param dir the file directory - * @param name the filename - * @return true if the filename matches one of the regular expressions - */ - public boolean accept(File dir, String name) { - return (pattern.matcher(name).matches()); - } - -} diff --git a/src/org/apache/commons/io/filefilter/SizeFileFilter.java b/src/org/apache/commons/io/filefilter/SizeFileFilter.java deleted file mode 100644 index 614e4243f..000000000 --- a/src/org/apache/commons/io/filefilter/SizeFileFilter.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * Filters files based on size, can filter either smaller files or - * files equal to or larger than a given threshold. - *

- * For example, to print all files and directories in the - * current directory whose size is greater than 1 MB: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( new SizeFileFilter(1024 * 1024) );
- * for ( int i = 0; i < files.length; i++ ) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @author Rahul Akolkar - * @version $Id: SizeFileFilter.java 591058 2007-11-01 15:47:05Z niallp $ - * @since Commons IO 1.2 - */ -public class SizeFileFilter extends AbstractFileFilter implements Serializable { - - /** The size threshold. */ - private final long size; - /** Whether the files accepted will be larger or smaller. */ - private final boolean acceptLarger; - - /** - * Constructs a new size file filter for files equal to or - * larger than a certain size. - * - * @param size the threshold size of the files - * @throws IllegalArgumentException if the size is negative - */ - public SizeFileFilter(long size) { - this(size, true); - } - - /** - * Constructs a new size file filter for files based on a certain size - * threshold. - * - * @param size the threshold size of the files - * @param acceptLarger if true, files equal to or larger are accepted, - * otherwise smaller ones (but not equal to) - * @throws IllegalArgumentException if the size is negative - */ - public SizeFileFilter(long size, boolean acceptLarger) { - if (size < 0) { - throw new IllegalArgumentException("The size must be non-negative"); - } - this.size = size; - this.acceptLarger = acceptLarger; - } - - //----------------------------------------------------------------------- - /** - * Checks to see if the size of the file is favorable. - *

- * If size equals threshold and smaller files are required, - * file IS NOT selected. - * If size equals threshold and larger files are required, - * file IS selected. - * - * @param file the File to check - * @return true if the filename matches - */ - public boolean accept(File file) { - boolean smaller = file.length() < size; - return acceptLarger ? !smaller : smaller; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - String condition = acceptLarger ? ">=" : "<"; - return super.toString() + "(" + condition + size + ")"; - } - -} diff --git a/src/org/apache/commons/io/filefilter/SuffixFileFilter.java b/src/org/apache/commons/io/filefilter/SuffixFileFilter.java deleted file mode 100644 index bee34402c..000000000 --- a/src/org/apache/commons/io/filefilter/SuffixFileFilter.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.List; - -import org.apache.commons.io.IOCase; - -/** - * Filters files based on the suffix (what the filename ends with). - * This is used in retrieving all the files of a particular type. - *

- * For example, to retrieve and print all *.java files - * in the current directory: - * - *

- * File dir = new File(".");
- * String[] files = dir.list( new SuffixFileFilter(".java") );
- * for (int i = 0; i < files.length; i++) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since Commons IO 1.0 - * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $ - * - * @author Stephen Colebourne - * @author Federico Barbieri - * @author Serge Knystautas - * @author Peter Donald - */ -public class SuffixFileFilter extends AbstractFileFilter implements Serializable { - - /** The filename suffixes to search for */ - private final String[] suffixes; - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Constructs a new Suffix file filter for a single extension. - * - * @param suffix the suffix to allow, must not be null - * @throws IllegalArgumentException if the suffix is null - */ - public SuffixFileFilter(String suffix) { - this(suffix, IOCase.SENSITIVE); - } - - /** - * Constructs a new Suffix file filter for a single extension - * specifying case-sensitivity. - * - * @param suffix the suffix to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the suffix is null - * @since Commons IO 1.4 - */ - public SuffixFileFilter(String suffix, IOCase caseSensitivity) { - if (suffix == null) { - throw new IllegalArgumentException("The suffix must not be null"); - } - this.suffixes = new String[] {suffix}; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Constructs a new Suffix file filter for an array of suffixs. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param suffixes the suffixes to allow, must not be null - * @throws IllegalArgumentException if the suffix array is null - */ - public SuffixFileFilter(String[] suffixes) { - this(suffixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Suffix file filter for an array of suffixs - * specifying case-sensitivity. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param suffixes the suffixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the suffix array is null - * @since Commons IO 1.4 - */ - public SuffixFileFilter(String[] suffixes, IOCase caseSensitivity) { - if (suffixes == null) { - throw new IllegalArgumentException("The array of suffixes must not be null"); - } - this.suffixes = suffixes; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Constructs a new Suffix file filter for a list of suffixes. - * - * @param suffixes the suffixes to allow, must not be null - * @throws IllegalArgumentException if the suffix list is null - * @throws ClassCastException if the list does not contain Strings - */ - public SuffixFileFilter(List suffixes) { - this(suffixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Suffix file filter for a list of suffixes - * specifying case-sensitivity. - * - * @param suffixes the suffixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the suffix list is null - * @throws ClassCastException if the list does not contain Strings - * @since Commons IO 1.4 - */ - public SuffixFileFilter(List suffixes, IOCase caseSensitivity) { - if (suffixes == null) { - throw new IllegalArgumentException("The list of suffixes must not be null"); - } - this.suffixes = (String[]) suffixes.toArray(new String[suffixes.size()]); - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Checks to see if the filename ends with the suffix. - * - * @param file the File to check - * @return true if the filename ends with one of our suffixes - */ - public boolean accept(File file) { - String name = file.getName(); - for (int i = 0; i < this.suffixes.length; i++) { - if (caseSensitivity.checkEndsWith(name, suffixes[i])) { - return true; - } - } - return false; - } - - /** - * Checks to see if the filename ends with the suffix. - * - * @param file the File directory - * @param name the filename - * @return true if the filename ends with one of our suffixes - */ - public boolean accept(File file, String name) { - for (int i = 0; i < this.suffixes.length; i++) { - if (caseSensitivity.checkEndsWith(name, suffixes[i])) { - return true; - } - } - return false; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(super.toString()); - buffer.append("("); - if (suffixes != null) { - for (int i = 0; i < suffixes.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(suffixes[i]); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/TrueFileFilter.java b/src/org/apache/commons/io/filefilter/TrueFileFilter.java deleted file mode 100644 index be1b13a7e..000000000 --- a/src/org/apache/commons/io/filefilter/TrueFileFilter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; - -/** - * A file filter that always returns true. - * - * @since Commons IO 1.0 - * @version $Revision: 587978 $ $Date: 2007-10-24 20:36:51 +0100 (Wed, 24 Oct 2007) $ - * - * @author Stephen Colebourne - */ -public class TrueFileFilter implements IOFileFilter, Serializable { - - /** - * Singleton instance of true filter. - * @since Commons IO 1.3 - */ - public static final IOFileFilter TRUE = new TrueFileFilter(); - /** - * Singleton instance of true filter. - * Please use the identical TrueFileFilter.TRUE constant. - * The new name is more JDK 1.5 friendly as it doesn't clash with other - * values when using static imports. - */ - public static final IOFileFilter INSTANCE = TRUE; - - /** - * Restrictive consructor. - */ - protected TrueFileFilter() { - } - - /** - * Returns true. - * - * @param file the file to check - * @return true - */ - public boolean accept(File file) { - return true; - } - - /** - * Returns true. - * - * @param dir the directory to check - * @param name the filename - * @return true - */ - public boolean accept(File dir, String name) { - return true; - } - -} diff --git a/src/org/apache/commons/io/filefilter/WildcardFileFilter.java b/src/org/apache/commons/io/filefilter/WildcardFileFilter.java deleted file mode 100644 index 791fe985b..000000000 --- a/src/org/apache/commons/io/filefilter/WildcardFileFilter.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.List; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOCase; - -/** - * Filters files using the supplied wildcards. - *

- * This filter selects files and directories based on one or more wildcards. - * Testing is case-sensitive by default, but this can be configured. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The extension check is case-sensitive by . - * See {@link FilenameUtils#wildcardMatchOnSystem} for more information. - *

- * For example: - *

- * File dir = new File(".");
- * FileFilter fileFilter = new WildcardFileFilter("*test*.java~*~");
- * File[] files = dir.listFiles(fileFilter);
- * for (int i = 0; i < files.length; i++) {
- *   System.out.println(files[i]);
- * }
- * 
- * - * @author Jason Anderson - * @version $Revision: 155419 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $ - * @since Commons IO 1.3 - */ -public class WildcardFileFilter extends AbstractFileFilter implements Serializable { - - /** The wildcards that will be used to match filenames. */ - private final String[] wildcards; - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Construct a new case-sensitive wildcard filter for a single wildcard. - * - * @param wildcard the wildcard to match - * @throws IllegalArgumentException if the pattern is null - */ - public WildcardFileFilter(String wildcard) { - this(wildcard, null); - } - - /** - * Construct a new wildcard filter for a single wildcard specifying case-sensitivity. - * - * @param wildcard the wildcard to match, not null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern is null - */ - public WildcardFileFilter(String wildcard, IOCase caseSensitivity) { - if (wildcard == null) { - throw new IllegalArgumentException("The wildcard must not be null"); - } - this.wildcards = new String[] { wildcard }; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Construct a new case-sensitive wildcard filter for an array of wildcards. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param wildcards the array of wildcards to match - * @throws IllegalArgumentException if the pattern array is null - */ - public WildcardFileFilter(String[] wildcards) { - this(wildcards, null); - } - - /** - * Construct a new wildcard filter for an array of wildcards specifying case-sensitivity. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param wildcards the array of wildcards to match, not null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern array is null - */ - public WildcardFileFilter(String[] wildcards, IOCase caseSensitivity) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard array must not be null"); - } - this.wildcards = wildcards; - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - /** - * Construct a new case-sensitive wildcard filter for a list of wildcards. - * - * @param wildcards the list of wildcards to match, not null - * @throws IllegalArgumentException if the pattern list is null - * @throws ClassCastException if the list does not contain Strings - */ - public WildcardFileFilter(List wildcards) { - this(wildcards, null); - } - - /** - * Construct a new wildcard filter for a list of wildcards specifying case-sensitivity. - * - * @param wildcards the list of wildcards to match, not null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern list is null - * @throws ClassCastException if the list does not contain Strings - */ - public WildcardFileFilter(List wildcards, IOCase caseSensitivity) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard list must not be null"); - } - this.wildcards = (String[]) wildcards.toArray(new String[wildcards.size()]); - this.caseSensitivity = (caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity); - } - - //----------------------------------------------------------------------- - /** - * Checks to see if the filename matches one of the wildcards. - * - * @param dir the file directory - * @param name the filename - * @return true if the filename matches one of the wildcards - */ - public boolean accept(File dir, String name) { - for (int i = 0; i < wildcards.length; i++) { - if (FilenameUtils.wildcardMatch(name, wildcards[i], caseSensitivity)) { - return true; - } - } - return false; - } - - /** - * Checks to see if the filename matches one of the wildcards. - * - * @param file the file to check - * @return true if the filename matches one of the wildcards - */ - public boolean accept(File file) { - String name = file.getName(); - for (int i = 0; i < wildcards.length; i++) { - if (FilenameUtils.wildcardMatch(name, wildcards[i], caseSensitivity)) { - return true; - } - } - return false; - } - - /** - * Provide a String representaion of this file filter. - * - * @return a String representaion - */ - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(super.toString()); - buffer.append("("); - if (wildcards != null) { - for (int i = 0; i < wildcards.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(wildcards[i]); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/WildcardFilter.java b/src/org/apache/commons/io/filefilter/WildcardFilter.java deleted file mode 100644 index 2a6e0dde0..000000000 --- a/src/org/apache/commons/io/filefilter/WildcardFilter.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.util.List; - -import org.apache.commons.io.FilenameUtils; - -/** - * Filters files using the supplied wildcards. - *

- * This filter selects files, but not directories, based on one or more wildcards - * and using case-sensitive comparison. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The extension check is case-sensitive. - * See {@link FilenameUtils#wildcardMatch} for more information. - *

- * For example: - *

- * File dir = new File(".");
- * FileFilter fileFilter = new WildcardFilter("*test*.java~*~");
- * File[] files = dir.listFiles(fileFilter);
- * for (int i = 0; i < files.length; i++) {
- *   System.out.println(files[i]);
- * }
- * 
- * - * @author Jason Anderson - * @version $Revision: 606381 $ $Date: 2007-12-22 02:03:16 +0000 (Sat, 22 Dec 2007) $ - * @since Commons IO 1.1 - * @deprecated Use WilcardFileFilter. Deprecated as this class performs directory - * filtering which it shouldn't do, but that can't be removed due to compatability. - */ -public class WildcardFilter extends AbstractFileFilter implements Serializable { - - /** The wildcards that will be used to match filenames. */ - private final String[] wildcards; - - /** - * Construct a new case-sensitive wildcard filter for a single wildcard. - * - * @param wildcard the wildcard to match - * @throws IllegalArgumentException if the pattern is null - */ - public WildcardFilter(String wildcard) { - if (wildcard == null) { - throw new IllegalArgumentException("The wildcard must not be null"); - } - this.wildcards = new String[] { wildcard }; - } - - /** - * Construct a new case-sensitive wildcard filter for an array of wildcards. - * - * @param wildcards the array of wildcards to match - * @throws IllegalArgumentException if the pattern array is null - */ - public WildcardFilter(String[] wildcards) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard array must not be null"); - } - this.wildcards = wildcards; - } - - /** - * Construct a new case-sensitive wildcard filter for a list of wildcards. - * - * @param wildcards the list of wildcards to match - * @throws IllegalArgumentException if the pattern list is null - * @throws ClassCastException if the list does not contain Strings - */ - public WildcardFilter(List wildcards) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard list must not be null"); - } - this.wildcards = (String[]) wildcards.toArray(new String[wildcards.size()]); - } - - //----------------------------------------------------------------------- - /** - * Checks to see if the filename matches one of the wildcards. - * - * @param dir the file directory - * @param name the filename - * @return true if the filename matches one of the wildcards - */ - public boolean accept(File dir, String name) { - if (dir != null && new File(dir, name).isDirectory()) { - return false; - } - - for (int i = 0; i < wildcards.length; i++) { - if (FilenameUtils.wildcardMatch(name, wildcards[i])) { - return true; - } - } - - return false; - } - - /** - * Checks to see if the filename matches one of the wildcards. - * - * @param file the file to check - * @return true if the filename matches one of the wildcards - */ - public boolean accept(File file) { - if (file.isDirectory()) { - return false; - } - - for (int i = 0; i < wildcards.length; i++) { - if (FilenameUtils.wildcardMatch(file.getName(), wildcards[i])) { - return true; - } - } - - return false; - } - -} diff --git a/src/org/apache/commons/io/filefilter/package.html b/src/org/apache/commons/io/filefilter/package.html deleted file mode 100644 index 7a45f251d..000000000 --- a/src/org/apache/commons/io/filefilter/package.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - -

This package defines an interface (IOFileFilter) that combines both -{@link java.io.FileFilter} and {@link java.io.FilenameFilter}. Besides -that the package offers a series of ready-to-use implementations of the -IOFileFilter interface including implementation that allow you to combine -other such filters.

-

These filter can be used to list files or in {@link java.awt.FileDialog}, -for example.

- -

There are a number of 'primitive' filters:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DirectoryFilterOnly accept directories
PrefixFileFilterFilter based on a prefix
SuffixFileFilterFilter based on a suffix
NameFileFilterFilter based on a filename
WildcardFileFilterFilter based on wildcards
AgeFileFilterFilter based on last modified time of file
SizeFileFilterFilter based on file size
- -

And there are five 'boolean' filters:

- - - - - - - - - - - - - - - - - - - - - - - - - -
TrueFileFilterAccept all files
FalseFileFilterAccept no files
NotFileFilterApplies a logical NOT to an existing filter
AndFileFilterCombines two filters using a logical AND
OrFileFilterCombines two filter using a logical OR
- -

These boolean FilenameFilters can be nested, to allow arbitrary expressions. -For example, here is how one could print all non-directory files in the -current directory, starting with "A", and ending in ".java" or ".class":

- -
-  File dir = new File(".");
-  String[] files = dir.list( 
-    new AndFileFilter(
-      new AndFileFilter(
-        new PrefixFileFilter("A"),
-        new OrFileFilter(
-          new SuffixFileFilter(".class"),
-          new SuffixFileFilter(".java")
-        )
-      ),
-      new NotFileFilter(
-        new DirectoryFileFilter()
-      )
-    )
-  );
-  for ( int i=0; i<files.length; i++ ) {
-    System.out.println(files[i]);
-  }
-
- -

This package also contains a utility class: -FileFilterUtils. It allows you to use all -file filters without having to put them in the import section. Here's how the -above example will look using FileFilterUtils:

-
-  File dir = new File(".");
-  String[] files = dir.list( 
-    FileFilterUtils.andFileFilter(
-      FileFilterUtils.andFileFilter(
-        FileFilterUtils.prefixFileFilter("A"),
-        FileFilterUtils.orFileFilter(
-          FileFilterUtils.suffixFileFilter(".class"),
-          FileFilterUtils.suffixFileFilter(".java")
-        )
-      ),
-      FileFilterUtils.notFileFilter(
-        FileFilterUtils.directoryFileFilter()
-      )
-    )
-  );
-  for ( int i=0; i<files.length; i++ ) {
-    System.out.println(files[i]);
-  }
-
-

There are a few other goodies in that class so please have a look at the -documentation in detail.

- - diff --git a/src/org/apache/commons/io/input/AutoCloseInputStream.java b/src/org/apache/commons/io/input/AutoCloseInputStream.java deleted file mode 100644 index bb62358f7..000000000 --- a/src/org/apache/commons/io/input/AutoCloseInputStream.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Proxy stream that closes and discards the underlying stream as soon as the - * end of input has been reached or when the stream is explicitly closed. - * Not even a reference to the underlying stream is kept after it has been - * closed, so any allocated in-memory buffers can be freed even if the - * client application still keeps a reference to the proxy stream. - *

- * This class is typically used to release any resources related to an open - * stream as soon as possible even if the client application (by not explicitly - * closing the stream when no longer needed) or the underlying stream (by not - * releasing resources once the last byte has been read) do not do that. - * - * @version $Id: AutoCloseInputStream.java 610010 2008-01-08 14:50:59Z niallp $ - * @since Commons IO 1.4 - */ -public class AutoCloseInputStream extends ProxyInputStream { - - /** - * Creates an automatically closing proxy for the given input stream. - * - * @param in underlying input stream - */ - public AutoCloseInputStream(InputStream in) { - super(in); - } - - /** - * Closes the underlying input stream and replaces the reference to it - * with a {@link ClosedInputStream} instance. - *

- * This method is automatically called by the read methods when the end - * of input has been reached. - *

- * Note that it is safe to call this method any number of times. The original - * underlying input stream is closed and discarded only once when this - * method is first called. - * - * @throws IOException if the underlying input stream can not be closed - */ - public void close() throws IOException { - in.close(); - in = new ClosedInputStream(); - } - - /** - * Reads and returns a single byte from the underlying input stream. - * If the underlying stream returns -1, the {@link #close()} method is - * called to automatically close and discard the stream. - * - * @return next byte in the stream, or -1 if no more bytes are available - * @throws IOException if the stream could not be read or closed - */ - public int read() throws IOException { - int n = in.read(); - if (n == -1) { - close(); - } - return n; - } - - /** - * Reads and returns bytes from the underlying input stream to the given - * buffer. If the underlying stream returns -1, the {@link #close()} method - * i called to automatically close and discard the stream. - * - * @param b buffer to which bytes from the stream are written - * @return number of bytes read, or -1 if no more bytes are available - * @throws IOException if the stream could not be read or closed - */ - public int read(byte[] b) throws IOException { - int n = in.read(b); - if (n == -1) { - close(); - } - return n; - } - - /** - * Reads and returns bytes from the underlying input stream to the given - * buffer. If the underlying stream returns -1, the {@link #close()} method - * i called to automatically close and discard the stream. - * - * @param b buffer to which bytes from the stream are written - * @param off start offset within the buffer - * @param len maximum number of bytes to read - * @return number of bytes read, or -1 if no more bytes are available - * @throws IOException if the stream could not be read or closed - */ - public int read(byte[] b, int off, int len) throws IOException { - int n = in.read(b, off, len); - if (n == -1) { - close(); - } - return n; - } - - /** - * Ensures that the stream is closed before it gets garbage-collected. - * As mentioned in {@link #close()}, this is a no-op if the stream has - * already been closed. - * @throws Throwable if an error occurs - */ - protected void finalize() throws Throwable { - close(); - super.finalize(); - } - -} diff --git a/src/org/apache/commons/io/input/CharSequenceReader.java b/src/org/apache/commons/io/input/CharSequenceReader.java deleted file mode 100644 index 6ee11d87d..000000000 --- a/src/org/apache/commons/io/input/CharSequenceReader.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.Reader; -import java.io.Serializable; - -/** - * {@link Reader} implementation that can read from String, StringBuffer, - * StringBuilder or CharBuffer. - *

- * Note: Supports {@link #mark(int)} and {@link #reset()}. - * - * @version $Revision: 610516 $ $Date: 2008-01-09 19:05:05 +0000 (Wed, 09 Jan 2008) $ - * @since Commons IO 1.4 - */ -public class CharSequenceReader extends Reader implements Serializable { - - private final CharSequence charSequence; - private int idx; - private int mark; - - /** - * Construct a new instance with the specified character sequence. - * - * @param charSequence The character sequence, may be null - */ - public CharSequenceReader(CharSequence charSequence) { - this.charSequence = (charSequence != null ? charSequence : ""); - } - - /** - * Close resets the file back to the start and removes any marked position. - */ - public void close() { - idx = 0; - mark = 0; - } - - /** - * Mark the current position. - * - * @param readAheadLimit ignored - */ - public void mark(int readAheadLimit) { - mark = idx; - } - - /** - * Mark is supported (returns true). - * - * @return true - */ - public boolean markSupported() { - return true; - } - - /** - * Read a single character. - * - * @return the next character from the character sequence - * or -1 if the end has been reached. - */ - public int read() { - if (idx >= charSequence.length()) { - return -1; - } else { - return charSequence.charAt(idx++); - } - } - - /** - * Read the sepcified number of characters into the array. - * - * @param array The array to store the characters in - * @param offset The starting position in the array to store - * @param length The maximum number of characters to read - * @return The number of characters read or -1 if there are - * no more - */ - public int read(char[] array, int offset, int length) { - if (idx >= charSequence.length()) { - return -1; - } - if (array == null) { - throw new NullPointerException("Character array is missing"); - } - if (length < 0 || (offset + length) > array.length) { - throw new IndexOutOfBoundsException("Array Size=" + array.length + - ", offset=" + offset + ", length=" + length); - } - int count = 0; - for (int i = 0; i < length; i++) { - int c = read(); - if (c == -1) { - return count; - } - array[offset + i] = (char)c; - count++; - } - return count; - } - - /** - * Reset the reader to the last marked position (or the beginning if - * mark has not been called). - */ - public void reset() { - idx = mark; - } - - /** - * Skip the specified number of characters. - * - * @param n The number of characters to skip - * @return The actual number of characters skipped - */ - public long skip(long n) { - if (n < 0) { - throw new IllegalArgumentException( - "Number of characters to skip is less than zero: " + n); - } - if (idx >= charSequence.length()) { - return -1; - } - int dest = (int)Math.min(charSequence.length(), (idx + n)); - int count = dest - idx; - idx = dest; - return count; - } - - /** - * Return a String representation of the underlying - * character sequence. - * - * @return The contents of the character sequence - */ - public String toString() { - return charSequence.toString(); - } -} diff --git a/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java b/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java deleted file mode 100644 index 13d048946..000000000 --- a/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectStreamClass; -import java.io.StreamCorruptedException; - -/** - * A special ObjectInputStream that loads a class based on a specified - * ClassLoader rather than the system default. - *

- * This is useful in dynamic container environments. - * - * @author Paul Hammant - * @version $Id: ClassLoaderObjectInputStream.java 437567 2006-08-28 06:39:07Z bayard $ - * @since Commons IO 1.1 - */ -public class ClassLoaderObjectInputStream extends ObjectInputStream { - - /** The class loader to use. */ - private ClassLoader classLoader; - - /** - * Constructs a new ClassLoaderObjectInputStream. - * - * @param classLoader the ClassLoader from which classes should be loaded - * @param inputStream the InputStream to work on - * @throws IOException in case of an I/O error - * @throws StreamCorruptedException if the stream is corrupted - */ - public ClassLoaderObjectInputStream( - ClassLoader classLoader, InputStream inputStream) - throws IOException, StreamCorruptedException { - super(inputStream); - this.classLoader = classLoader; - } - - /** - * Resolve a class specified by the descriptor using the - * specified ClassLoader or the super ClassLoader. - * - * @param objectStreamClass descriptor of the class - * @return the Class object described by the ObjectStreamClass - * @throws IOException in case of an I/O error - * @throws ClassNotFoundException if the Class cannot be found - */ - protected Class resolveClass(ObjectStreamClass objectStreamClass) - throws IOException, ClassNotFoundException { - - Class clazz = Class.forName(objectStreamClass.getName(), false, classLoader); - - if (clazz != null) { - // the classloader knows of the class - return clazz; - } else { - // classloader knows not of class, let the super classloader do it - return super.resolveClass(objectStreamClass); - } - } -} diff --git a/src/org/apache/commons/io/input/CloseShieldInputStream.java b/src/org/apache/commons/io/input/CloseShieldInputStream.java deleted file mode 100644 index 2058beeb2..000000000 --- a/src/org/apache/commons/io/input/CloseShieldInputStream.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.InputStream; - -/** - * Proxy stream that prevents the underlying input stream from being closed. - *

- * This class is typically used in cases where an input stream needs to be - * passed to a component that wants to explicitly close the stream even if - * more input would still be available to other components. - * - * @version $Id: CloseShieldInputStream.java 587913 2007-10-24 15:47:30Z niallp $ - * @since Commons IO 1.4 - */ -public class CloseShieldInputStream extends ProxyInputStream { - - /** - * Creates a proxy that shields the given input stream from being - * closed. - * - * @param in underlying input stream - */ - public CloseShieldInputStream(InputStream in) { - super(in); - } - - /** - * Replaces the underlying input stream with a {@link ClosedInputStream} - * sentinel. The original input stream will remain open, but this proxy - * will appear closed. - */ - public void close() { - in = new ClosedInputStream(); - } - -} diff --git a/src/org/apache/commons/io/input/ClosedInputStream.java b/src/org/apache/commons/io/input/ClosedInputStream.java deleted file mode 100644 index 86c83c903..000000000 --- a/src/org/apache/commons/io/input/ClosedInputStream.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.InputStream; - -/** - * Closed input stream. This stream returns -1 to all attempts to read - * something from the stream. - *

- * Typically uses of this class include testing for corner cases in methods - * that accept input streams and acting as a sentinel value instead of a - * null input stream. - * - * @version $Id: ClosedInputStream.java 601751 2007-12-06 14:55:45Z niallp $ - * @since Commons IO 1.4 - */ -public class ClosedInputStream extends InputStream { - - /** - * A singleton. - */ - public static final ClosedInputStream CLOSED_INPUT_STREAM = new ClosedInputStream(); - - /** - * Returns -1 to indicate that the stream is closed. - * - * @return always -1 - */ - public int read() { - return -1; - } - -} diff --git a/src/org/apache/commons/io/input/CountingInputStream.java b/src/org/apache/commons/io/input/CountingInputStream.java deleted file mode 100644 index 2782276c8..000000000 --- a/src/org/apache/commons/io/input/CountingInputStream.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A decorating input stream that counts the number of bytes that have passed - * through the stream so far. - *

- * A typical use case would be during debugging, to ensure that data is being - * read as expected. - * - * @author Marcelo Liberato - * @version $Id: CountingInputStream.java 471628 2006-11-06 04:06:45Z bayard $ - */ -public class CountingInputStream extends ProxyInputStream { - - /** The count of bytes that have passed. */ - private long count; - - /** - * Constructs a new CountingInputStream. - * - * @param in the InputStream to delegate to - */ - public CountingInputStream(InputStream in) { - super(in); - } - - //----------------------------------------------------------------------- - /** - * Reads a number of bytes into the byte array, keeping count of the - * number read. - * - * @param b the buffer into which the data is read, not null - * @return the total number of bytes read into the buffer, -1 if end of stream - * @throws IOException if an I/O error occurs - * @see java.io.InputStream#read(byte[]) - */ - public int read(byte[] b) throws IOException { - int found = super.read(b); - this.count += (found >= 0) ? found : 0; - return found; - } - - /** - * Reads a number of bytes into the byte array at a specific offset, - * keeping count of the number read. - * - * @param b the buffer into which the data is read, not null - * @param off the start offset in the buffer - * @param len the maximum number of bytes to read - * @return the total number of bytes read into the buffer, -1 if end of stream - * @throws IOException if an I/O error occurs - * @see java.io.InputStream#read(byte[], int, int) - */ - public int read(byte[] b, int off, int len) throws IOException { - int found = super.read(b, off, len); - this.count += (found >= 0) ? found : 0; - return found; - } - - /** - * Reads the next byte of data adding to the count of bytes received - * if a byte is successfully read. - * - * @return the byte read, -1 if end of stream - * @throws IOException if an I/O error occurs - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - int found = super.read(); - this.count += (found >= 0) ? 1 : 0; - return found; - } - - /** - * Skips the stream over the specified number of bytes, adding the skipped - * amount to the count. - * - * @param length the number of bytes to skip - * @return the actual number of bytes skipped - * @throws IOException if an I/O error occurs - * @see java.io.InputStream#skip(long) - */ - public long skip(final long length) throws IOException { - final long skip = super.skip(length); - this.count += skip; - return skip; - } - - //----------------------------------------------------------------------- - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an int. - * See {@link #getByteCount()} for a method using a long. - * - * @return the number of bytes accumulated - * @throws ArithmeticException if the byte count is too large - */ - public synchronized int getCount() { - long result = getByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an int. - * See {@link #resetByteCount()} for a method using a long. - * - * @return the count previous to resetting - * @throws ArithmeticException if the byte count is too large - */ - public synchronized int resetCount() { - long result = resetByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: This method is an alternative for getCount() - * and was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the number of bytes accumulated - * @since Commons IO 1.3 - */ - public synchronized long getByteCount() { - return this.count; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: This method is an alternative for resetCount() - * and was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the count previous to resetting - * @since Commons IO 1.3 - */ - public synchronized long resetByteCount() { - long tmp = this.count; - this.count = 0; - return tmp; - } - -} diff --git a/src/org/apache/commons/io/input/DemuxInputStream.java b/src/org/apache/commons/io/input/DemuxInputStream.java deleted file mode 100644 index 1ae888916..000000000 --- a/src/org/apache/commons/io/input/DemuxInputStream.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Data written to this stream is forwarded to a stream that has been associated - * with this thread. - * - * @author Peter Donald - * @version $Revision: 437567 $ $Date: 2006-08-28 07:39:07 +0100 (Mon, 28 Aug 2006) $ - */ -public class DemuxInputStream - extends InputStream -{ - private InheritableThreadLocal m_streams = new InheritableThreadLocal(); - - /** - * Bind the specified stream to the current thread. - * - * @param input the stream to bind - * @return the InputStream that was previously active - */ - public InputStream bindStream( InputStream input ) - { - InputStream oldValue = getStream(); - m_streams.set( input ); - return oldValue; - } - - /** - * Closes stream associated with current thread. - * - * @throws IOException if an error occurs - */ - public void close() - throws IOException - { - InputStream input = getStream(); - if( null != input ) - { - input.close(); - } - } - - /** - * Read byte from stream associated with current thread. - * - * @return the byte read from stream - * @throws IOException if an error occurs - */ - public int read() - throws IOException - { - InputStream input = getStream(); - if( null != input ) - { - return input.read(); - } - else - { - return -1; - } - } - - /** - * Utility method to retrieve stream bound to current thread (if any). - * - * @return the input stream - */ - private InputStream getStream() - { - return (InputStream)m_streams.get(); - } -} diff --git a/src/org/apache/commons/io/input/NullInputStream.java b/src/org/apache/commons/io/input/NullInputStream.java deleted file mode 100644 index 7cee2c6d0..000000000 --- a/src/org/apache/commons/io/input/NullInputStream.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -/** - * A functional, light weight {@link InputStream} that emulates - * a stream of a specified size. - *

- * This implementation provides a light weight - * object for testing with an {@link InputStream} - * where the contents don't matter. - *

- * One use case would be for testing the handling of - * large {@link InputStream} as it can emulate that - * scenario without the overhead of actually processing - * large numbers of bytes - significantly speeding up - * test execution times. - *

- * This implementation returns zero from the method that - * reads a byte and leaves the array unchanged in the read - * methods that are passed a byte array. - * If alternative data is required the processByte() and - * processBytes() methods can be implemented to generate - * data, for example: - * - *

- *  public class TestInputStream extends NullInputStream {
- *      public TestInputStream(int size) {
- *          super(size);
- *      }
- *      protected int processByte() {
- *          return ... // return required value here
- *      }
- *      protected void processBytes(byte[] bytes, int offset, int length) {
- *          for (int i = offset; i < length; i++) {
- *              bytes[i] = ... // set array value here
- *          }
- *      }
- *  }
- * 
- * - * @since Commons IO 1.3 - * @version $Revision: 463529 $ - */ -public class NullInputStream extends InputStream { - - private long size; - private long position; - private long mark = -1; - private long readlimit; - private boolean eof; - private boolean throwEofException; - private boolean markSupported; - - /** - * Create an {@link InputStream} that emulates a specified size - * which supports marking and does not throw EOFException. - * - * @param size The size of the input stream to emulate. - */ - public NullInputStream(long size) { - this(size, true, false); - } - - /** - * Create an {@link InputStream} that emulates a specified - * size with option settings. - * - * @param size The size of the input stream to emulate. - * @param markSupported Whether this instance will support - * the mark() functionality. - * @param throwEofException Whether this implementation - * will throw an {@link EOFException} or return -1 when the - * end of file is reached. - */ - public NullInputStream(long size, boolean markSupported, boolean throwEofException) { - this.size = size; - this.markSupported = markSupported; - this.throwEofException = throwEofException; - } - - /** - * Return the current position. - * - * @return the current position. - */ - public long getPosition() { - return position; - } - - /** - * Return the size this {@link InputStream} emulates. - * - * @return The size of the input stream to emulate. - */ - public long getSize() { - return size; - } - - /** - * Return the number of bytes that can be read. - * - * @return The number of bytes that can be read. - */ - public int available() { - long avail = size - position; - if (avail <= 0) { - return 0; - } else if (avail > Integer.MAX_VALUE) { - return Integer.MAX_VALUE; - } else { - return (int)avail; - } - } - - /** - * Close this input stream - resets the internal state to - * the initial values. - * - * @throws IOException If an error occurs. - */ - public void close() throws IOException { - eof = false; - position = 0; - mark = -1; - } - - /** - * Mark the current position. - * - * @param readlimit The number of bytes before this marked position - * is invalid. - * @throws UnsupportedOperationException if mark is not supported. - */ - public synchronized void mark(int readlimit) { - if (!markSupported) { - throw new UnsupportedOperationException("Mark not supported"); - } - mark = position; - this.readlimit = readlimit; - } - - /** - * Indicates whether mark is supported. - * - * @return Whether mark is supported or not. - */ - public boolean markSupported() { - return markSupported; - } - - /** - * Read a byte. - * - * @return Either The byte value returned by processByte() - * or -1 if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public int read() throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position++; - return processByte(); - } - - /** - * Read some bytes into the specified array. - * - * @param bytes The byte array to read into - * @return The number of bytes read or -1 - * if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public int read(byte[] bytes) throws IOException { - return read(bytes, 0, bytes.length); - } - - /** - * Read the specified number bytes into an array. - * - * @param bytes The byte array to read into. - * @param offset The offset to start reading bytes into. - * @param length The number of bytes to read. - * @return The number of bytes read or -1 - * if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public int read(byte[] bytes, int offset, int length) throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += length; - int returnLength = length; - if (position > size) { - returnLength = length - (int)(position - size); - position = size; - } - processBytes(bytes, offset, returnLength); - return returnLength; - } - - /** - * Reset the stream to the point when mark was last called. - * - * @throws UnsupportedOperationException if mark is not supported. - * @throws IOException If no position has been marked - * or the read limit has been exceed since the last position was - * marked. - */ - public synchronized void reset() throws IOException { - if (!markSupported) { - throw new UnsupportedOperationException("Mark not supported"); - } - if (mark < 0) { - throw new IOException("No position has been marked"); - } - if (position > (mark + readlimit)) { - throw new IOException("Marked position [" + mark + - "] is no longer valid - passed the read limit [" + - readlimit + "]"); - } - position = mark; - eof = false; - } - - /** - * Skip a specified number of bytes. - * - * @param numberOfBytes The number of bytes to skip. - * @return The number of bytes skipped or -1 - * if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public long skip(long numberOfBytes) throws IOException { - if (eof) { - throw new IOException("Skip after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += numberOfBytes; - long returnLength = numberOfBytes; - if (position > size) { - returnLength = numberOfBytes - (position - size); - position = size; - } - return returnLength; - } - - /** - * Return a byte value for the read() method. - *

- * This implementation returns zero. - * - * @return This implementation always returns zero. - */ - protected int processByte() { - // do nothing - overridable by subclass - return 0; - } - - /** - * Process the bytes for the read(byte[], offset, length) - * method. - *

- * This implementation leaves the byte array unchanged. - * - * @param bytes The byte array - * @param offset The offset to start at. - * @param length The number of bytes. - */ - protected void processBytes(byte[] bytes, int offset, int length) { - // do nothing - overridable by subclass - } - - /** - * Handle End of File. - * - * @return -1 if throwEofException is - * set to false - * @throws EOFException if throwEofException is set - * to true. - */ - private int doEndOfFile() throws EOFException { - eof = true; - if (throwEofException) { - throw new EOFException(); - } - return -1; - } - -} diff --git a/src/org/apache/commons/io/input/NullReader.java b/src/org/apache/commons/io/input/NullReader.java deleted file mode 100644 index 159e39021..000000000 --- a/src/org/apache/commons/io/input/NullReader.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.EOFException; -import java.io.IOException; -import java.io.Reader; - -/** - * A functional, light weight {@link Reader} that emulates - * a reader of a specified size. - *

- * This implementation provides a light weight - * object for testing with an {@link Reader} - * where the contents don't matter. - *

- * One use case would be for testing the handling of - * large {@link Reader} as it can emulate that - * scenario without the overhead of actually processing - * large numbers of characters - significantly speeding up - * test execution times. - *

- * This implementation returns a space from the method that - * reads a character and leaves the array unchanged in the read - * methods that are passed a character array. - * If alternative data is required the processChar() and - * processChars() methods can be implemented to generate - * data, for example: - * - *

- *  public class TestReader extends NullReader {
- *      public TestReader(int size) {
- *          super(size);
- *      }
- *      protected char processChar() {
- *          return ... // return required value here
- *      }
- *      protected void processChars(char[] chars, int offset, int length) {
- *          for (int i = offset; i < length; i++) {
- *              chars[i] = ... // set array value here
- *          }
- *      }
- *  }
- * 
- * - * @since Commons IO 1.3 - * @version $Revision: 463529 $ - */ -public class NullReader extends Reader { - - private long size; - private long position; - private long mark = -1; - private long readlimit; - private boolean eof; - private boolean throwEofException; - private boolean markSupported; - - /** - * Create a {@link Reader} that emulates a specified size - * which supports marking and does not throw EOFException. - * - * @param size The size of the reader to emulate. - */ - public NullReader(long size) { - this(size, true, false); - } - - /** - * Create a {@link Reader} that emulates a specified - * size with option settings. - * - * @param size The size of the reader to emulate. - * @param markSupported Whether this instance will support - * the mark() functionality. - * @param throwEofException Whether this implementation - * will throw an {@link EOFException} or return -1 when the - * end of file is reached. - */ - public NullReader(long size, boolean markSupported, boolean throwEofException) { - this.size = size; - this.markSupported = markSupported; - this.throwEofException = throwEofException; - } - - /** - * Return the current position. - * - * @return the current position. - */ - public long getPosition() { - return position; - } - - /** - * Return the size this {@link Reader} emulates. - * - * @return The size of the reader to emulate. - */ - public long getSize() { - return size; - } - - /** - * Close this Reader - resets the internal state to - * the initial values. - * - * @throws IOException If an error occurs. - */ - public void close() throws IOException { - eof = false; - position = 0; - mark = -1; - } - - /** - * Mark the current position. - * - * @param readlimit The number of characters before this marked position - * is invalid. - * @throws UnsupportedOperationException if mark is not supported. - */ - public synchronized void mark(int readlimit) { - if (!markSupported) { - throw new UnsupportedOperationException("Mark not supported"); - } - mark = position; - this.readlimit = readlimit; - } - - /** - * Indicates whether mark is supported. - * - * @return Whether mark is supported or not. - */ - public boolean markSupported() { - return markSupported; - } - - /** - * Read a character. - * - * @return Either The character value returned by processChar() - * or -1 if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public int read() throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position++; - return processChar(); - } - - /** - * Read some characters into the specified array. - * - * @param chars The character array to read into - * @return The number of characters read or -1 - * if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public int read(char[] chars) throws IOException { - return read(chars, 0, chars.length); - } - - /** - * Read the specified number characters into an array. - * - * @param chars The character array to read into. - * @param offset The offset to start reading characters into. - * @param length The number of characters to read. - * @return The number of characters read or -1 - * if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public int read(char[] chars, int offset, int length) throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += length; - int returnLength = length; - if (position > size) { - returnLength = length - (int)(position - size); - position = size; - } - processChars(chars, offset, returnLength); - return returnLength; - } - - /** - * Reset the stream to the point when mark was last called. - * - * @throws UnsupportedOperationException if mark is not supported. - * @throws IOException If no position has been marked - * or the read limit has been exceed since the last position was - * marked. - */ - public synchronized void reset() throws IOException { - if (!markSupported) { - throw new UnsupportedOperationException("Mark not supported"); - } - if (mark < 0) { - throw new IOException("No position has been marked"); - } - if (position > (mark + readlimit)) { - throw new IOException("Marked position [" + mark + - "] is no longer valid - passed the read limit [" + - readlimit + "]"); - } - position = mark; - eof = false; - } - - /** - * Skip a specified number of characters. - * - * @param numberOfChars The number of characters to skip. - * @return The number of characters skipped or -1 - * if the end of file has been reached and - * throwEofException is set to false. - * @throws EOFException if the end of file is reached and - * throwEofException is set to true. - * @throws IOException if trying to read past the end of file. - */ - public long skip(long numberOfChars) throws IOException { - if (eof) { - throw new IOException("Skip after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += numberOfChars; - long returnLength = numberOfChars; - if (position > size) { - returnLength = numberOfChars - (position - size); - position = size; - } - return returnLength; - } - - /** - * Return a character value for the read() method. - *

- * This implementation returns zero. - * - * @return This implementation always returns zero. - */ - protected int processChar() { - // do nothing - overridable by subclass - return 0; - } - - /** - * Process the characters for the read(char[], offset, length) - * method. - *

- * This implementation leaves the character array unchanged. - * - * @param chars The character array - * @param offset The offset to start at. - * @param length The number of characters. - */ - protected void processChars(char[] chars, int offset, int length) { - // do nothing - overridable by subclass - } - - /** - * Handle End of File. - * - * @return -1 if throwEofException is - * set to false - * @throws EOFException if throwEofException is set - * to true. - */ - private int doEndOfFile() throws EOFException { - eof = true; - if (throwEofException) { - throw new EOFException(); - } - return -1; - } - -} diff --git a/src/org/apache/commons/io/input/ProxyInputStream.java b/src/org/apache/commons/io/input/ProxyInputStream.java deleted file mode 100644 index a08ad92d0..000000000 --- a/src/org/apache/commons/io/input/ProxyInputStream.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * A Proxy stream which acts as expected, that is it passes the method - * calls on to the proxied stream and doesn't change which methods are - * being called. - *

- * It is an alternative base class to FilterInputStream - * to increase reusability, because FilterInputStream changes the - * methods being called, such as read(byte[]) to read(byte[], int, int). - * - * @author Stephen Colebourne - * @version $Id: ProxyInputStream.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public abstract class ProxyInputStream extends FilterInputStream { - - /** - * Constructs a new ProxyInputStream. - * - * @param proxy the InputStream to delegate to - */ - public ProxyInputStream(InputStream proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'in' - } - - /** - * Invokes the delegate's read() method. - * @return the byte read or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public int read() throws IOException { - return in.read(); - } - - /** - * Invokes the delegate's read(byte[]) method. - * @param bts the buffer to read the bytes into - * @return the number of bytes read or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public int read(byte[] bts) throws IOException { - return in.read(bts); - } - - /** - * Invokes the delegate's read(byte[], int, int) method. - * @param bts the buffer to read the bytes into - * @param st The start offset - * @param end The number of bytes to read - * @return the number of bytes read or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public int read(byte[] bts, int st, int end) throws IOException { - return in.read(bts, st, end); - } - - /** - * Invokes the delegate's skip(long) method. - * @param ln the number of bytes to skip - * @return the number of bytes to skipped or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public long skip(long ln) throws IOException { - return in.skip(ln); - } - - /** - * Invokes the delegate's available() method. - * @return the number of available bytes - * @throws IOException if an I/O error occurs - */ - public int available() throws IOException { - return in.available(); - } - - /** - * Invokes the delegate's close() method. - * @throws IOException if an I/O error occurs - */ - public void close() throws IOException { - in.close(); - } - - /** - * Invokes the delegate's mark(int) method. - * @param idx read ahead limit - */ - public synchronized void mark(int idx) { - in.mark(idx); - } - - /** - * Invokes the delegate's reset() method. - * @throws IOException if an I/O error occurs - */ - public synchronized void reset() throws IOException { - in.reset(); - } - - /** - * Invokes the delegate's markSupported() method. - * @return true if mark is supported, otherwise false - */ - public boolean markSupported() { - return in.markSupported(); - } - -} diff --git a/src/org/apache/commons/io/input/ProxyReader.java b/src/org/apache/commons/io/input/ProxyReader.java deleted file mode 100644 index d55290f5a..000000000 --- a/src/org/apache/commons/io/input/ProxyReader.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.FilterReader; -import java.io.IOException; -import java.io.Reader; - -/** - * A Proxy stream which acts as expected, that is it passes the method - * calls on to the proxied stream and doesn't change which methods are - * being called. - *

- * It is an alternative base class to FilterReader - * to increase reusability, because FilterReader changes the - * methods being called, such as read(char[]) to read(char[], int, int). - * - * @author Stephen Colebourne - * @version $Id: ProxyReader.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public abstract class ProxyReader extends FilterReader { - - /** - * Constructs a new ProxyReader. - * - * @param proxy the Reader to delegate to - */ - public ProxyReader(Reader proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'in' - } - - /** - * Invokes the delegate's read() method. - * @return the character read or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public int read() throws IOException { - return in.read(); - } - - /** - * Invokes the delegate's read(char[]) method. - * @param chr the buffer to read the characters into - * @return the number of characters read or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public int read(char[] chr) throws IOException { - return in.read(chr); - } - - /** - * Invokes the delegate's read(char[], int, int) method. - * @param chr the buffer to read the characters into - * @param st The start offset - * @param end The number of bytes to read - * @return the number of characters read or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public int read(char[] chr, int st, int end) throws IOException { - return in.read(chr, st, end); - } - - /** - * Invokes the delegate's skip(long) method. - * @param ln the number of bytes to skip - * @return the number of bytes to skipped or -1 if the end of stream - * @throws IOException if an I/O error occurs - */ - public long skip(long ln) throws IOException { - return in.skip(ln); - } - - /** - * Invokes the delegate's ready() method. - * @return true if the stream is ready to be read - * @throws IOException if an I/O error occurs - */ - public boolean ready() throws IOException { - return in.ready(); - } - - /** - * Invokes the delegate's close() method. - * @throws IOException if an I/O error occurs - */ - public void close() throws IOException { - in.close(); - } - - /** - * Invokes the delegate's mark(int) method. - * @param idx read ahead limit - * @throws IOException if an I/O error occurs - */ - public synchronized void mark(int idx) throws IOException { - in.mark(idx); - } - - /** - * Invokes the delegate's reset() method. - * @throws IOException if an I/O error occurs - */ - public synchronized void reset() throws IOException { - in.reset(); - } - - /** - * Invokes the delegate's markSupported() method. - * @return true if mark is supported, otherwise false - */ - public boolean markSupported() { - return in.markSupported(); - } - -} diff --git a/src/org/apache/commons/io/input/SwappedDataInputStream.java b/src/org/apache/commons/io/input/SwappedDataInputStream.java deleted file mode 100644 index 5b65b1eee..000000000 --- a/src/org/apache/commons/io/input/SwappedDataInputStream.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.DataInput; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.io.EndianUtils; - -/** - * DataInput for systems relying on little endian data formats. - * When read, values will be changed from little endian to big - * endian formats for internal usage. - *

- * Origin of code: Avalon Excalibur (IO) - * - * @author Peter Donald - * @version CVS $Revision: 610010 $ $Date: 2008-01-08 14:50:59 +0000 (Tue, 08 Jan 2008) $ - */ -public class SwappedDataInputStream extends ProxyInputStream - implements DataInput -{ - - /** - * Constructs a SwappedDataInputStream. - * - * @param input InputStream to read from - */ - public SwappedDataInputStream( InputStream input ) - { - super( input ); - } - - /** - * Return {@link #readByte()} == 0 - * @return the true if the byte read is zero, otherwise false - * @throws IOException if an I/O error occurs - * @throws EOFException if an end of file is reached unexpectedly - */ - public boolean readBoolean() - throws IOException, EOFException - { - return ( 0 == readByte() ); - } - - /** - * Invokes the delegate's read() method. - * @return the byte read or -1 if the end of stream - * @throws IOException if an I/O error occurs - * @throws EOFException if an end of file is reached unexpectedly - */ - public byte readByte() - throws IOException, EOFException - { - return (byte)in.read(); - } - - /** - * Reads a character delegating to {@link #readShort()}. - * @return the byte read or -1 if the end of stream - * @throws IOException if an I/O error occurs - * @throws EOFException if an end of file is reached unexpectedly - */ - public char readChar() - throws IOException, EOFException - { - return (char)readShort(); - } - - /** - * Delegates to {@link EndianUtils#readSwappedDouble(InputStream)}. - * @return the read long - * @throws IOException if an I/O error occurs - * @throws EOFException if an end of file is reached unexpectedly - */ - public double readDouble() - throws IOException, EOFException - { - return EndianUtils.readSwappedDouble( in ); - } - - /** - * Delegates to {@link EndianUtils#readSwappedFloat(InputStream)}. - * @return the read long - * @throws IOException if an I/O error occurs - * @throws EOFException if an end of file is reached unexpectedly - */ - public float readFloat() - throws IOException, EOFException - { - return EndianUtils.readSwappedFloat( in ); - } - - /** - * Invokes the delegate's read(byte[] data, int, int) method. - * - * @param data the buffer to read the bytes into - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public void readFully( byte[] data ) - throws IOException, EOFException - { - readFully( data, 0, data.length ); - } - - - /** - * Invokes the delegate's read(byte[] data, int, int) method. - * - * @param data the buffer to read the bytes into - * @param offset The start offset - * @param length The number of bytes to read - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public void readFully( byte[] data, int offset, int length ) - throws IOException, EOFException - { - int remaining = length; - - while( remaining > 0 ) - { - int location = offset + ( length - remaining ); - int count = read( data, location, remaining ); - - if( -1 == count ) - { - throw new EOFException(); - } - - remaining -= count; - } - } - - /** - * Delegates to {@link EndianUtils#readSwappedInteger(InputStream)}. - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public int readInt() - throws IOException, EOFException - { - return EndianUtils.readSwappedInteger( in ); - } - - /** - * Not currently supported - throws {@link UnsupportedOperationException}. - * @return the line read - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public String readLine() - throws IOException, EOFException - { - throw new UnsupportedOperationException( - "Operation not supported: readLine()" ); - } - - /** - * Delegates to {@link EndianUtils#readSwappedLong(InputStream)}. - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public long readLong() - throws IOException, EOFException - { - return EndianUtils.readSwappedLong( in ); - } - - /** - * Delegates to {@link EndianUtils#readSwappedShort(InputStream)}. - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public short readShort() - throws IOException, EOFException - { - return EndianUtils.readSwappedShort( in ); - } - - /** - * Invokes the delegate's read() method. - * @return the byte read or -1 if the end of stream - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public int readUnsignedByte() - throws IOException, EOFException - { - return in.read(); - } - - /** - * Delegates to {@link EndianUtils#readSwappedUnsignedShort(InputStream)}. - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public int readUnsignedShort() - throws IOException, EOFException - { - return EndianUtils.readSwappedUnsignedShort( in ); - } - - /** - * Not currently supported - throws {@link UnsupportedOperationException}. - * @return UTF String read - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public String readUTF() - throws IOException, EOFException - { - throw new UnsupportedOperationException( - "Operation not supported: readUTF()" ); - } - - /** - * Invokes the delegate's skip(int) method. - * @param count the number of bytes to skip - * @return the number of bytes to skipped or -1 if the end of stream - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs - */ - public int skipBytes( int count ) - throws IOException, EOFException - { - return (int)in.skip( count ); - } - -} diff --git a/src/org/apache/commons/io/input/TeeInputStream.java b/src/org/apache/commons/io/input/TeeInputStream.java deleted file mode 100644 index fed000ed6..000000000 --- a/src/org/apache/commons/io/input/TeeInputStream.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * InputStream proxy that transparently writes a copy of all bytes read - * from the proxied stream to a given OutputStream. Using {@link #skip(long)} - * or {@link #mark(int)}/{@link #reset()} on the stream will result on some - * bytes from the input stream being skipped or duplicated in the output - * stream. - *

- * The proxied input stream is closed when the {@link #close()} method is - * called on this proxy. It is configurable whether the associated output - * stream will also closed. - * - * @version $Id: TeeInputStream.java 587913 2007-10-24 15:47:30Z niallp $ - * @since Commons IO 1.4 - */ -public class TeeInputStream extends ProxyInputStream { - - /** - * The output stream that will receive a copy of all bytes read from the - * proxied input stream. - */ - private final OutputStream branch; - - /** - * Flag for closing also the associated output stream when this - * stream is closed. - */ - private final boolean closeBranch; - - /** - * Creates a TeeInputStream that proxies the given {@link InputStream} - * and copies all read bytes to the given {@link OutputStream}. The given - * output stream will not be closed when this stream gets closed. - * - * @param input input stream to be proxied - * @param branch output stream that will receive a copy of all bytes read - */ - public TeeInputStream(InputStream input, OutputStream branch) { - this(input, branch, false); - } - - /** - * Creates a TeeInputStream that proxies the given {@link InputStream} - * and copies all read bytes to the given {@link OutputStream}. The given - * output stream will be closed when this stream gets closed if the - * closeBranch parameter is true. - * - * @param input input stream to be proxied - * @param branch output stream that will receive a copy of all bytes read - * @param closeBranch flag for closing also the output stream when this - * stream is closed - */ - public TeeInputStream( - InputStream input, OutputStream branch, boolean closeBranch) { - super(input); - this.branch = branch; - this.closeBranch = closeBranch; - } - - /** - * Closes the proxied input stream and, if so configured, the associated - * output stream. An exception thrown from one stream will not prevent - * closing of the other stream. - * - * @throws IOException if either of the streams could not be closed - */ - public void close() throws IOException { - try { - super.close(); - } finally { - if (closeBranch) { - branch.close(); - } - } - } - - /** - * Reads a single byte from the proxied input stream and writes it to - * the associated output stream. - * - * @return next byte from the stream, or -1 if the stream has ended - * @throws IOException if the stream could not be read (or written) - */ - public int read() throws IOException { - int ch = super.read(); - if (ch != -1) { - branch.write(ch); - } - return ch; - } - - /** - * Reads bytes from the proxied input stream and writes the read bytes - * to the associated output stream. - * - * @param bts byte buffer - * @param st start offset within the buffer - * @param end maximum number of bytes to read - * @return number of bytes read, or -1 if the stream has ended - * @throws IOException if the stream could not be read (or written) - */ - public int read(byte[] bts, int st, int end) throws IOException { - int n = super.read(bts, st, end); - if (n != -1) { - branch.write(bts, st, n); - } - return n; - } - - /** - * Reads bytes from the proxied input stream and writes the read bytes - * to the associated output stream. - * - * @param bts byte buffer - * @return number of bytes read, or -1 if the stream has ended - * @throws IOException if the stream could not be read (or written) - */ - public int read(byte[] bts) throws IOException { - int n = super.read(bts); - if (n != -1) { - branch.write(bts, 0, n); - } - return n; - } - -} diff --git a/src/org/apache/commons/io/input/package.html b/src/org/apache/commons/io/input/package.html deleted file mode 100644 index 9aa8b15ba..000000000 --- a/src/org/apache/commons/io/input/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - -

-This package provides implementations of input classes, such as -InputStream and Reader. -

- - diff --git a/src/org/apache/commons/io/output/ByteArrayOutputStream.java b/src/org/apache/commons/io/output/ByteArrayOutputStream.java deleted file mode 100644 index 66d5e8dc3..000000000 --- a/src/org/apache/commons/io/output/ByteArrayOutputStream.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.List; - -/** - * This class implements an output stream in which the data is - * written into a byte array. The buffer automatically grows as data - * is written to it. - *

- * The data can be retrieved using toByteArray() and - * toString(). - *

- * Closing a ByteArrayOutputStream has no effect. The methods in - * this class can be called after the stream has been closed without - * generating an IOException. - *

- * This is an alternative implementation of the java.io.ByteArrayOutputStream - * class. The original implementation only allocates 32 bytes at the beginning. - * As this class is designed for heavy duty it starts at 1024 bytes. In contrast - * to the original it doesn't reallocate the whole memory block but allocates - * additional buffers. This way no buffers need to be garbage collected and - * the contents don't have to be copied to the new buffer. This class is - * designed to behave exactly like the original. The only exception is the - * deprecated toString(int) method that has been ignored. - * - * @author Jeremias Maerki - * @author Holger Hoffstatte - * @version $Id: ByteArrayOutputStream.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public class ByteArrayOutputStream extends OutputStream { - - /** A singleton empty byte array. */ - private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - - /** The list of buffers, which grows and never reduces. */ - private List buffers = new ArrayList(); - /** The index of the current buffer. */ - private int currentBufferIndex; - /** The total count of bytes in all the filled buffers. */ - private int filledBufferSum; - /** The current buffer. */ - private byte[] currentBuffer; - /** The total count of bytes written. */ - private int count; - - /** - * Creates a new byte array output stream. The buffer capacity is - * initially 1024 bytes, though its size increases if necessary. - */ - public ByteArrayOutputStream() { - this(1024); - } - - /** - * Creates a new byte array output stream, with a buffer capacity of - * the specified size, in bytes. - * - * @param size the initial size - * @throws IllegalArgumentException if size is negative - */ - public ByteArrayOutputStream(int size) { - if (size < 0) { - throw new IllegalArgumentException( - "Negative initial size: " + size); - } - needNewBuffer(size); - } - - /** - * Return the appropriate byte[] buffer - * specified by index. - * - * @param index the index of the buffer required - * @return the buffer - */ - private byte[] getBuffer(int index) { - return (byte[]) buffers.get(index); - } - - /** - * Makes a new buffer available either by allocating - * a new one or re-cycling an existing one. - * - * @param newcount the size of the buffer if one is created - */ - private void needNewBuffer(int newcount) { - if (currentBufferIndex < buffers.size() - 1) { - //Recycling old buffer - filledBufferSum += currentBuffer.length; - - currentBufferIndex++; - currentBuffer = getBuffer(currentBufferIndex); - } else { - //Creating new buffer - int newBufferSize; - if (currentBuffer == null) { - newBufferSize = newcount; - filledBufferSum = 0; - } else { - newBufferSize = Math.max( - currentBuffer.length << 1, - newcount - filledBufferSum); - filledBufferSum += currentBuffer.length; - } - - currentBufferIndex++; - currentBuffer = new byte[newBufferSize]; - buffers.add(currentBuffer); - } - } - - /** - * Write the bytes to byte array. - * @param b the bytes to write - * @param off The start offset - * @param len The number of bytes to write - */ - public void write(byte[] b, int off, int len) { - if ((off < 0) - || (off > b.length) - || (len < 0) - || ((off + len) > b.length) - || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - synchronized (this) { - int newcount = count + len; - int remaining = len; - int inBufferPos = count - filledBufferSum; - while (remaining > 0) { - int part = Math.min(remaining, currentBuffer.length - inBufferPos); - System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part); - remaining -= part; - if (remaining > 0) { - needNewBuffer(newcount); - inBufferPos = 0; - } - } - count = newcount; - } - } - - /** - * Write a byte to byte array. - * @param b the byte to write - */ - public synchronized void write(int b) { - int inBufferPos = count - filledBufferSum; - if (inBufferPos == currentBuffer.length) { - needNewBuffer(count + 1); - inBufferPos = 0; - } - currentBuffer[inBufferPos] = (byte) b; - count++; - } - - /** - * Writes the entire contents of the specified input stream to this - * byte stream. Bytes from the input stream are read directly into the - * internal buffers of this streams. - * - * @param in the input stream to read from - * @return total number of bytes read from the input stream - * (and written to this stream) - * @throws IOException if an I/O error occurs while reading the input stream - * @since Commons IO 1.4 - */ - public synchronized int write(InputStream in) throws IOException { - int readCount = 0; - int inBufferPos = count - filledBufferSum; - int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); - while (n != -1) { - readCount += n; - inBufferPos += n; - count += n; - if (inBufferPos == currentBuffer.length) { - needNewBuffer(currentBuffer.length); - inBufferPos = 0; - } - n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); - } - return readCount; - } - - /** - * Return the current size of the byte array. - * @return the current size of the byte array - */ - public synchronized int size() { - return count; - } - - /** - * Closing a ByteArrayOutputStream has no effect. The methods in - * this class can be called after the stream has been closed without - * generating an IOException. - * - * @throws IOException never (this method should not declare this exception - * but it has to now due to backwards compatability) - */ - public void close() throws IOException { - //nop - } - - /** - * @see java.io.ByteArrayOutputStream#reset() - */ - public synchronized void reset() { - count = 0; - filledBufferSum = 0; - currentBufferIndex = 0; - currentBuffer = getBuffer(currentBufferIndex); - } - - /** - * Writes the entire contents of this byte stream to the - * specified output stream. - * - * @param out the output stream to write to - * @throws IOException if an I/O error occurs, such as if the stream is closed - * @see java.io.ByteArrayOutputStream#writeTo(OutputStream) - */ - public synchronized void writeTo(OutputStream out) throws IOException { - int remaining = count; - for (int i = 0; i < buffers.size(); i++) { - byte[] buf = getBuffer(i); - int c = Math.min(buf.length, remaining); - out.write(buf, 0, c); - remaining -= c; - if (remaining == 0) { - break; - } - } - } - - /** - * Gets the curent contents of this byte stream as a byte array. - * The result is independent of this stream. - * - * @return the current contents of this output stream, as a byte array - * @see java.io.ByteArrayOutputStream#toByteArray() - */ - public synchronized byte[] toByteArray() { - int remaining = count; - if (remaining == 0) { - return EMPTY_BYTE_ARRAY; - } - byte newbuf[] = new byte[remaining]; - int pos = 0; - for (int i = 0; i < buffers.size(); i++) { - byte[] buf = getBuffer(i); - int c = Math.min(buf.length, remaining); - System.arraycopy(buf, 0, newbuf, pos, c); - pos += c; - remaining -= c; - if (remaining == 0) { - break; - } - } - return newbuf; - } - - /** - * Gets the curent contents of this byte stream as a string. - * @return the contents of the byte array as a String - * @see java.io.ByteArrayOutputStream#toString() - */ - public String toString() { - return new String(toByteArray()); - } - - /** - * Gets the curent contents of this byte stream as a string - * using the specified encoding. - * - * @param enc the name of the character encoding - * @return the string converted from the byte array - * @throws UnsupportedEncodingException if the encoding is not supported - * @see java.io.ByteArrayOutputStream#toString(String) - */ - public String toString(String enc) throws UnsupportedEncodingException { - return new String(toByteArray(), enc); - } - -} diff --git a/src/org/apache/commons/io/output/CloseShieldOutputStream.java b/src/org/apache/commons/io/output/CloseShieldOutputStream.java deleted file mode 100644 index 63f44be40..000000000 --- a/src/org/apache/commons/io/output/CloseShieldOutputStream.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.OutputStream; - -/** - * Proxy stream that prevents the underlying output stream from being closed. - *

- * This class is typically used in cases where an output stream needs to be - * passed to a component that wants to explicitly close the stream even if - * other components would still use the stream for output. - * - * @version $Id: CloseShieldOutputStream.java 587913 2007-10-24 15:47:30Z niallp $ - * @since Commons IO 1.4 - */ -public class CloseShieldOutputStream extends ProxyOutputStream { - - /** - * Creates a proxy that shields the given output stream from being - * closed. - * - * @param out underlying output stream - */ - public CloseShieldOutputStream(OutputStream out) { - super(out); - } - - /** - * Replaces the underlying output stream with a {@link ClosedOutputStream} - * sentinel. The original output stream will remain open, but this proxy - * will appear closed. - */ - public void close() { - out = new ClosedOutputStream(); - } - -} diff --git a/src/org/apache/commons/io/output/ClosedOutputStream.java b/src/org/apache/commons/io/output/ClosedOutputStream.java deleted file mode 100644 index b585c0cf4..000000000 --- a/src/org/apache/commons/io/output/ClosedOutputStream.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Closed output stream. This stream throws an exception on all attempts to - * write something to the stream. - *

- * Typically uses of this class include testing for corner cases in methods - * that accept an output stream and acting as a sentinel value instead of - * a null output stream. - * - * @version $Id: ClosedOutputStream.java 601751 2007-12-06 14:55:45Z niallp $ - * @since Commons IO 1.4 - */ -public class ClosedOutputStream extends OutputStream { - - /** - * A singleton. - */ - public static final ClosedOutputStream CLOSED_OUTPUT_STREAM = new ClosedOutputStream(); - - /** - * Throws an {@link IOException} to indicate that the stream is closed. - * - * @param b ignored - * @throws IOException always thrown - */ - public void write(int b) throws IOException { - throw new IOException("write(" + b + ") failed: stream is closed"); - } - -} diff --git a/src/org/apache/commons/io/output/CountingOutputStream.java b/src/org/apache/commons/io/output/CountingOutputStream.java deleted file mode 100644 index 672882860..000000000 --- a/src/org/apache/commons/io/output/CountingOutputStream.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * A decorating output stream that counts the number of bytes that have passed - * through the stream so far. - *

- * A typical use case would be during debugging, to ensure that data is being - * written as expected. - * - * @version $Id: CountingOutputStream.java 471628 2006-11-06 04:06:45Z bayard $ - */ -public class CountingOutputStream extends ProxyOutputStream { - - /** The count of bytes that have passed. */ - private long count; - - /** - * Constructs a new CountingOutputStream. - * - * @param out the OutputStream to write to - */ - public CountingOutputStream( OutputStream out ) { - super(out); - } - - //----------------------------------------------------------------------- - /** - * Writes the contents of the specified byte array to this output stream - * keeping count of the number of bytes written. - * - * @param b the bytes to write, not null - * @throws IOException if an I/O error occurs - * @see java.io.OutputStream#write(byte[]) - */ - public void write(byte[] b) throws IOException { - count += b.length; - super.write(b); - } - - /** - * Writes a portion of the specified byte array to this output stream - * keeping count of the number of bytes written. - * - * @param b the bytes to write, not null - * @param off the start offset in the buffer - * @param len the maximum number of bytes to write - * @throws IOException if an I/O error occurs - * @see java.io.OutputStream#write(byte[], int, int) - */ - public void write(byte[] b, int off, int len) throws IOException { - count += len; - super.write(b, off, len); - } - - /** - * Writes a single byte to the output stream adding to the count of the - * number of bytes written. - * - * @param b the byte to write - * @throws IOException if an I/O error occurs - * @see java.io.OutputStream#write(int) - */ - public void write(int b) throws IOException { - count++; - super.write(b); - } - - //----------------------------------------------------------------------- - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an int. - * See {@link #getByteCount()} for a method using a long. - * - * @return the number of bytes accumulated - * @throws ArithmeticException if the byte count is too large - */ - public synchronized int getCount() { - long result = getByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an int. - * See {@link #resetByteCount()} for a method using a long. - * - * @return the count previous to resetting - * @throws ArithmeticException if the byte count is too large - */ - public synchronized int resetCount() { - long result = resetByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: This method is an alternative for getCount(). - * It was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the number of bytes accumulated - * @since Commons IO 1.3 - */ - public synchronized long getByteCount() { - return this.count; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: This method is an alternative for resetCount(). - * It was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the count previous to resetting - * @since Commons IO 1.3 - */ - public synchronized long resetByteCount() { - long tmp = this.count; - this.count = 0; - return tmp; - } - -} diff --git a/src/org/apache/commons/io/output/DeferredFileOutputStream.java b/src/org/apache/commons/io/output/DeferredFileOutputStream.java deleted file mode 100644 index b8a9e9607..000000000 --- a/src/org/apache/commons/io/output/DeferredFileOutputStream.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.io.IOUtils; - - -/** - * An output stream which will retain data in memory until a specified - * threshold is reached, and only then commit it to disk. If the stream is - * closed before the threshold is reached, the data will not be written to - * disk at all. - *

- * This class originated in FileUpload processing. In this use case, you do - * not know in advance the size of the file being uploaded. If the file is small - * you want to store it in memory (for speed), but if the file is large you want - * to store it to file (to avoid memory issues). - * - * @author Martin Cooper - * @author gaxzerow - * - * @version $Id: DeferredFileOutputStream.java 606381 2007-12-22 02:03:16Z ggregory $ - */ -public class DeferredFileOutputStream - extends ThresholdingOutputStream -{ - - // ----------------------------------------------------------- Data members - - - /** - * The output stream to which data will be written prior to the theshold - * being reached. - */ - private ByteArrayOutputStream memoryOutputStream; - - - /** - * The output stream to which data will be written at any given time. This - * will always be one of memoryOutputStream or - * diskOutputStream. - */ - private OutputStream currentOutputStream; - - - /** - * The file to which output will be directed if the threshold is exceeded. - */ - private File outputFile; - - /** - * The temporary file prefix. - */ - private String prefix; - - /** - * The temporary file suffix. - */ - private String suffix; - - /** - * The directory to use for temporary files. - */ - private File directory; - - - /** - * True when close() has been called successfully. - */ - private boolean closed = false; - - // ----------------------------------------------------------- Constructors - - - /** - * Constructs an instance of this class which will trigger an event at the - * specified threshold, and save data to a file beyond that point. - * - * @param threshold The number of bytes at which to trigger an event. - * @param outputFile The file to which data is saved beyond the threshold. - */ - public DeferredFileOutputStream(int threshold, File outputFile) - { - super(threshold); - this.outputFile = outputFile; - - memoryOutputStream = new ByteArrayOutputStream(); - currentOutputStream = memoryOutputStream; - } - - - /** - * Constructs an instance of this class which will trigger an event at the - * specified threshold, and save data to a temporary file beyond that point. - * - * @param threshold The number of bytes at which to trigger an event. - * @param prefix Prefix to use for the temporary file. - * @param suffix Suffix to use for the temporary file. - * @param directory Temporary file directory. - * - * @since Commons IO 1.4 - */ - public DeferredFileOutputStream(int threshold, String prefix, String suffix, File directory) - { - this(threshold, (File)null); - if (prefix == null) { - throw new IllegalArgumentException("Temporary file prefix is missing"); - } - this.prefix = prefix; - this.suffix = suffix; - this.directory = directory; - } - - - // --------------------------------------- ThresholdingOutputStream methods - - - /** - * Returns the current output stream. This may be memory based or disk - * based, depending on the current state with respect to the threshold. - * - * @return The underlying output stream. - * - * @exception IOException if an error occurs. - */ - protected OutputStream getStream() throws IOException - { - return currentOutputStream; - } - - - /** - * Switches the underlying output stream from a memory based stream to one - * that is backed by disk. This is the point at which we realise that too - * much data is being written to keep in memory, so we elect to switch to - * disk-based storage. - * - * @exception IOException if an error occurs. - */ - protected void thresholdReached() throws IOException - { - if (prefix != null) { - outputFile = File.createTempFile(prefix, suffix, directory); - } - FileOutputStream fos = new FileOutputStream(outputFile); - memoryOutputStream.writeTo(fos); - currentOutputStream = fos; - memoryOutputStream = null; - } - - - // --------------------------------------------------------- Public methods - - - /** - * Determines whether or not the data for this output stream has been - * retained in memory. - * - * @return true if the data is available in memory; - * false otherwise. - */ - public boolean isInMemory() - { - return (!isThresholdExceeded()); - } - - - /** - * Returns the data for this output stream as an array of bytes, assuming - * that the data has been retained in memory. If the data was written to - * disk, this method returns null. - * - * @return The data for this output stream, or null if no such - * data is available. - */ - public byte[] getData() - { - if (memoryOutputStream != null) - { - return memoryOutputStream.toByteArray(); - } - return null; - } - - - /** - * Returns either the output file specified in the constructor or - * the temporary file created or null. - *

- * If the constructor specifying the file is used then it returns that - * same output file, even when threashold has not been reached. - *

- * If constructor specifying a temporary file prefix/suffix is used - * then the temporary file created once the threashold is reached is returned - * If the threshold was not reached then null is returned. - * - * @return The file for this output stream, or null if no such - * file exists. - */ - public File getFile() - { - return outputFile; - } - - - /** - * Closes underlying output stream, and mark this as closed - * - * @exception IOException if an error occurs. - */ - public void close() throws IOException - { - super.close(); - closed = true; - } - - - /** - * Writes the data from this output stream to the specified output stream, - * after it has been closed. - * - * @param out output stream to write to. - * @exception IOException if this stream is not yet closed or an error occurs. - */ - public void writeTo(OutputStream out) throws IOException - { - // we may only need to check if this is closed if we are working with a file - // but we should force the habit of closing wether we are working with - // a file or memory. - if (!closed) - { - throw new IOException("Stream not closed"); - } - - if(isInMemory()) - { - memoryOutputStream.writeTo(out); - } - else - { - FileInputStream fis = new FileInputStream(outputFile); - try { - IOUtils.copy(fis, out); - } finally { - IOUtils.closeQuietly(fis); - } - } - } -} diff --git a/src/org/apache/commons/io/output/DemuxOutputStream.java b/src/org/apache/commons/io/output/DemuxOutputStream.java deleted file mode 100644 index 086911118..000000000 --- a/src/org/apache/commons/io/output/DemuxOutputStream.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Data written to this stream is forwarded to a stream that has been associated - * with this thread. - * - * @author Peter Donald - * @version $Revision: 437567 $ $Date: 2006-08-28 07:39:07 +0100 (Mon, 28 Aug 2006) $ - */ -public class DemuxOutputStream - extends OutputStream -{ - private InheritableThreadLocal m_streams = new InheritableThreadLocal(); - - /** - * Bind the specified stream to the current thread. - * - * @param output the stream to bind - * @return the OutputStream that was previously active - */ - public OutputStream bindStream( OutputStream output ) - { - OutputStream stream = getStream(); - m_streams.set( output ); - return stream; - } - - /** - * Closes stream associated with current thread. - * - * @throws IOException if an error occurs - */ - public void close() - throws IOException - { - OutputStream output = getStream(); - if( null != output ) - { - output.close(); - } - } - - /** - * Flushes stream associated with current thread. - * - * @throws IOException if an error occurs - */ - public void flush() - throws IOException - { - OutputStream output = getStream(); - if( null != output ) - { - output.flush(); - } - } - - /** - * Writes byte to stream associated with current thread. - * - * @param ch the byte to write to stream - * @throws IOException if an error occurs - */ - public void write( int ch ) - throws IOException - { - OutputStream output = getStream(); - if( null != output ) - { - output.write( ch ); - } - } - - /** - * Utility method to retrieve stream bound to current thread (if any). - * - * @return the output stream - */ - private OutputStream getStream() - { - return (OutputStream)m_streams.get(); - } -} diff --git a/src/org/apache/commons/io/output/FileWriterWithEncoding.java b/src/org/apache/commons/io/output/FileWriterWithEncoding.java deleted file mode 100644 index a8f89334b..000000000 --- a/src/org/apache/commons/io/output/FileWriterWithEncoding.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; - -/** - * Writer of files that allows the encoding to be set. - *

- * This class provides a simple alternative to FileWriter - * that allows an encoding to be set. Unfortunately, it cannot subclass - * FileWriter. - *

- * By default, the file will be overwritten, but this may be changed to append. - *

- * The encoding must be specified using either the name of the {@link Charset}, - * the {@link Charset}, or a {@link CharsetEncoder}. If the default encoding - * is required then use the {@link java.io.FileWriter} directly, rather than - * this implementation. - *

- * - * - * @since Commons IO 1.4 - * @version $Id: FileWriterWithEncoding.java 611634 2008-01-13 20:35:00Z niallp $ - */ -public class FileWriterWithEncoding extends Writer { - // Cannot extend ProxyWriter, as requires writer to be - // known when super() is called - - /** The writer to decorate. */ - private final Writer out; - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param filename the name of the file to write to, not null - * @param encoding the encoding to use, not null - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(String filename, String encoding) throws IOException { - this(new File(filename), encoding, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param filename the name of the file to write to, not null - * @param encoding the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(String filename, String encoding, boolean append) throws IOException { - this(new File(filename), encoding, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param filename the name of the file to write to, not null - * @param encoding the encoding to use, not null - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(String filename, Charset encoding) throws IOException { - this(new File(filename), encoding, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param filename the name of the file to write to, not null - * @param encoding the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(String filename, Charset encoding, boolean append) throws IOException { - this(new File(filename), encoding, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param filename the name of the file to write to, not null - * @param encoding the encoding to use, not null - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(String filename, CharsetEncoder encoding) throws IOException { - this(new File(filename), encoding, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param filename the name of the file to write to, not null - * @param encoding the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(String filename, CharsetEncoder encoding, boolean append) throws IOException { - this(new File(filename), encoding, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, not null - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(File file, String encoding) throws IOException { - this(file, encoding, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(File file, String encoding, boolean append) throws IOException { - super(); - this.out = initWriter(file, encoding, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, not null - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(File file, Charset encoding) throws IOException { - this(file, encoding, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(File file, Charset encoding, boolean append) throws IOException { - super(); - this.out = initWriter(file, encoding, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, not null - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(File file, CharsetEncoder encoding) throws IOException { - this(file, encoding, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(File file, CharsetEncoder encoding, boolean append) throws IOException { - super(); - this.out = initWriter(file, encoding, append); - } - - //----------------------------------------------------------------------- - /** - * Initialise the wrapped file writer. - * Ensure that a cleanup occurs if the writer creation fails. - * - * @param file the file to be accessed - * @param encoding the encoding to use - may be Charset, CharsetEncoder or String - * @param append true to append - * @return the initialised writer - * @throws NullPointerException if the file or encoding is null - * @throws IOException if an error occurs - */ - private static Writer initWriter(File file, Object encoding, boolean append) throws IOException { - if (file == null) { - throw new NullPointerException("File is missing"); - } - if (encoding == null) { - throw new NullPointerException("Encoding is missing"); - } - boolean fileExistedAlready = file.exists(); - OutputStream stream = null; - Writer writer = null; - try { - stream = new FileOutputStream(file, append); - if (encoding instanceof Charset) { - writer = new OutputStreamWriter(stream, (Charset)encoding); - } else if (encoding instanceof CharsetEncoder) { - writer = new OutputStreamWriter(stream, (CharsetEncoder)encoding); - } else { - writer = new OutputStreamWriter(stream, (String)encoding); - } - } catch (IOException ex) { - IOUtils.closeQuietly(writer); - IOUtils.closeQuietly(stream); - if (fileExistedAlready == false) { - FileUtils.deleteQuietly(file); - } - throw ex; - } catch (RuntimeException ex) { - IOUtils.closeQuietly(writer); - IOUtils.closeQuietly(stream); - if (fileExistedAlready == false) { - FileUtils.deleteQuietly(file); - } - throw ex; - } - return writer; - } - - //----------------------------------------------------------------------- - /** - * Write a character. - * @param idx the character to write - * @throws IOException if an I/O error occurs - */ - public void write(int idx) throws IOException { - out.write(idx); - } - - /** - * Write the characters from an array. - * @param chr the characters to write - * @throws IOException if an I/O error occurs - */ - public void write(char[] chr) throws IOException { - out.write(chr); - } - - /** - * Write the specified characters from an array. - * @param chr the characters to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs - */ - public void write(char[] chr, int st, int end) throws IOException { - out.write(chr, st, end); - } - - /** - * Write the characters from a string. - * @param str the string to write - * @throws IOException if an I/O error occurs - */ - public void write(String str) throws IOException { - out.write(str); - } - - /** - * Write the specified characters from a string. - * @param str the string to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs - */ - public void write(String str, int st, int end) throws IOException { - out.write(str, st, end); - } - - /** - * Flush the stream. - * @throws IOException if an I/O error occurs - */ - public void flush() throws IOException { - out.flush(); - } - - /** - * Close the stream. - * @throws IOException if an I/O error occurs - */ - public void close() throws IOException { - out.close(); - } -} diff --git a/src/org/apache/commons/io/output/LockableFileWriter.java b/src/org/apache/commons/io/output/LockableFileWriter.java deleted file mode 100644 index 6b10bd282..000000000 --- a/src/org/apache/commons/io/output/LockableFileWriter.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; - -/** - * FileWriter that will create and honor lock files to allow simple - * cross thread file lock handling. - *

- * This class provides a simple alternative to FileWriter - * that will use a lock file to prevent duplicate writes. - *

- * By default, the file will be overwritten, but this may be changed to append. - * The lock directory may be specified, but defaults to the system property - * java.io.tmpdir. - * The encoding may also be specified, and defaults to the platform default. - * - * @author Scott Sanders - * @author Michael Salmon - * @author Jon S. Stevens - * @author Daniel Rall - * @author Stephen Colebourne - * @author Andy Lehane - * @version $Id: LockableFileWriter.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public class LockableFileWriter extends Writer { - // Cannot extend ProxyWriter, as requires writer to be - // known when super() is called - - /** The extension for the lock file. */ - private static final String LCK = ".lck"; - - /** The writer to decorate. */ - private final Writer out; - /** The lock file. */ - private final File lockFile; - - /** - * Constructs a LockableFileWriter. - * If the file exists, it is overwritten. - * - * @param fileName the file to write to, not null - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(String fileName) throws IOException { - this(fileName, false, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param fileName file to write to, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(String fileName, boolean append) throws IOException { - this(fileName, append, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param fileName the file to write to, not null - * @param append true if content should be appended, false to overwrite - * @param lockDir the directory in which the lock file should be held - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(String fileName, boolean append, String lockDir) throws IOException { - this(new File(fileName), append, lockDir); - } - - /** - * Constructs a LockableFileWriter. - * If the file exists, it is overwritten. - * - * @param file the file to write to, not null - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(File file) throws IOException { - this(file, false, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param file the file to write to, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(File file, boolean append) throws IOException { - this(file, append, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param file the file to write to, not null - * @param append true if content should be appended, false to overwrite - * @param lockDir the directory in which the lock file should be held - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(File file, boolean append, String lockDir) throws IOException { - this(file, null, append, lockDir); - } - - /** - * Constructs a LockableFileWriter with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, null means platform default - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(File file, String encoding) throws IOException { - this(file, encoding, false, null); - } - - /** - * Constructs a LockableFileWriter with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the encoding to use, null means platform default - * @param append true if content should be appended, false to overwrite - * @param lockDir the directory in which the lock file should be held - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(File file, String encoding, boolean append, - String lockDir) throws IOException { - super(); - // init file to create/append - file = file.getAbsoluteFile(); - if (file.getParentFile() != null) { - FileUtils.forceMkdir(file.getParentFile()); - } - if (file.isDirectory()) { - throw new IOException("File specified is a directory"); - } - - // init lock file - if (lockDir == null) { - lockDir = System.getProperty("java.io.tmpdir"); - } - File lockDirFile = new File(lockDir); - FileUtils.forceMkdir(lockDirFile); - testLockDir(lockDirFile); - lockFile = new File(lockDirFile, file.getName() + LCK); - - // check if locked - createLock(); - - // init wrapped writer - out = initWriter(file, encoding, append); - } - - //----------------------------------------------------------------------- - /** - * Tests that we can write to the lock directory. - * - * @param lockDir the File representing the lock directory - * @throws IOException if we cannot write to the lock directory - * @throws IOException if we cannot find the lock file - */ - private void testLockDir(File lockDir) throws IOException { - if (!lockDir.exists()) { - throw new IOException( - "Could not find lockDir: " + lockDir.getAbsolutePath()); - } - if (!lockDir.canWrite()) { - throw new IOException( - "Could not write to lockDir: " + lockDir.getAbsolutePath()); - } - } - - /** - * Creates the lock file. - * - * @throws IOException if we cannot create the file - */ - private void createLock() throws IOException { - synchronized (LockableFileWriter.class) { - if (!lockFile.createNewFile()) { - throw new IOException("Can't write file, lock " + - lockFile.getAbsolutePath() + " exists"); - } - lockFile.deleteOnExit(); - } - } - - /** - * Initialise the wrapped file writer. - * Ensure that a cleanup occurs if the writer creation fails. - * - * @param file the file to be accessed - * @param encoding the encoding to use - * @param append true to append - * @return The initialised writer - * @throws IOException if an error occurs - */ - private Writer initWriter(File file, String encoding, boolean append) throws IOException { - boolean fileExistedAlready = file.exists(); - OutputStream stream = null; - Writer writer = null; - try { - if (encoding == null) { - writer = new FileWriter(file.getAbsolutePath(), append); - } else { - stream = new FileOutputStream(file.getAbsolutePath(), append); - writer = new OutputStreamWriter(stream, encoding); - } - } catch (IOException ex) { - IOUtils.closeQuietly(writer); - IOUtils.closeQuietly(stream); - lockFile.delete(); - if (fileExistedAlready == false) { - file.delete(); - } - throw ex; - } catch (RuntimeException ex) { - IOUtils.closeQuietly(writer); - IOUtils.closeQuietly(stream); - lockFile.delete(); - if (fileExistedAlready == false) { - file.delete(); - } - throw ex; - } - return writer; - } - - //----------------------------------------------------------------------- - /** - * Closes the file writer. - * - * @throws IOException if an I/O error occurs - */ - public void close() throws IOException { - try { - out.close(); - } finally { - lockFile.delete(); - } - } - - //----------------------------------------------------------------------- - /** - * Write a character. - * @param idx the character to write - * @throws IOException if an I/O error occurs - */ - public void write(int idx) throws IOException { - out.write(idx); - } - - /** - * Write the characters from an array. - * @param chr the characters to write - * @throws IOException if an I/O error occurs - */ - public void write(char[] chr) throws IOException { - out.write(chr); - } - - /** - * Write the specified characters from an array. - * @param chr the characters to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs - */ - public void write(char[] chr, int st, int end) throws IOException { - out.write(chr, st, end); - } - - /** - * Write the characters from a string. - * @param str the string to write - * @throws IOException if an I/O error occurs - */ - public void write(String str) throws IOException { - out.write(str); - } - - /** - * Write the specified characters from a string. - * @param str the string to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs - */ - public void write(String str, int st, int end) throws IOException { - out.write(str, st, end); - } - - /** - * Flush the stream. - * @throws IOException if an I/O error occurs - */ - public void flush() throws IOException { - out.flush(); - } - -} diff --git a/src/org/apache/commons/io/output/NullOutputStream.java b/src/org/apache/commons/io/output/NullOutputStream.java deleted file mode 100644 index 7e3cdaf2c..000000000 --- a/src/org/apache/commons/io/output/NullOutputStream.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * This OutputStream writes all data to the famous /dev/null. - *

- * This output stream has no destination (file/socket etc.) and all - * bytes written to it are ignored and lost. - * - * @author Jeremias Maerki - * @version $Id: NullOutputStream.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public class NullOutputStream extends OutputStream { - - /** - * A singleton. - */ - public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream(); - - /** - * Does nothing - output to /dev/null. - * @param b The bytes to write - * @param off The start offset - * @param len The number of bytes to write - */ - public void write(byte[] b, int off, int len) { - //to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * @param b The byte to write - */ - public void write(int b) { - //to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * @param b The bytes to write - * @throws IOException never - */ - public void write(byte[] b) throws IOException { - //to /dev/null - } - -} diff --git a/src/org/apache/commons/io/output/NullWriter.java b/src/org/apache/commons/io/output/NullWriter.java deleted file mode 100644 index aed52aba8..000000000 --- a/src/org/apache/commons/io/output/NullWriter.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.Writer; - -/** - * This {@link Writer} writes all data to the famous /dev/null. - *

- * This Writer has no destination (file/socket etc.) and all - * characters written to it are ignored and lost. - * - * @version $Id: NullWriter.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public class NullWriter extends Writer { - - /** - * A singleton. - */ - public static final NullWriter NULL_WRITER = new NullWriter(); - - /** - * Constructs a new NullWriter. - */ - public NullWriter() { - } - - /** - * Does nothing - output to /dev/null. - * @param idx The character to write - */ - public void write(int idx) { - //to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * @param chr The characters to write - */ - public void write(char[] chr) { - //to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * @param chr The characters to write - * @param st The start offset - * @param end The number of characters to write - */ - public void write(char[] chr, int st, int end) { - //to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * @param str The string to write - */ - public void write(String str) { - //to /dev/null - } - - /** - * Does nothing - output to /dev/null. - * @param str The string to write - * @param st The start offset - * @param end The number of characters to write - */ - public void write(String str, int st, int end) { - //to /dev/null - } - - /** @see java.io.Writer#flush() */ - public void flush() { - //to /dev/null - } - - /** @see java.io.Writer#close() */ - public void close() { - //to /dev/null - } - -} diff --git a/src/org/apache/commons/io/output/ProxyOutputStream.java b/src/org/apache/commons/io/output/ProxyOutputStream.java deleted file mode 100644 index b63d72317..000000000 --- a/src/org/apache/commons/io/output/ProxyOutputStream.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * A Proxy stream which acts as expected, that is it passes the method - * calls on to the proxied stream and doesn't change which methods are - * being called. It is an alternative base class to FilterOutputStream - * to increase reusability. - * - * @author Stephen Colebourne - * @version $Id: ProxyOutputStream.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public class ProxyOutputStream extends FilterOutputStream { - - /** - * Constructs a new ProxyOutputStream. - * - * @param proxy the OutputStream to delegate to - */ - public ProxyOutputStream(OutputStream proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'out' - } - - /** - * Invokes the delegate's write(int) method. - * @param idx the byte to write - * @throws IOException if an I/O error occurs - */ - public void write(int idx) throws IOException { - out.write(idx); - } - - /** - * Invokes the delegate's write(byte[]) method. - * @param bts the bytes to write - * @throws IOException if an I/O error occurs - */ - public void write(byte[] bts) throws IOException { - out.write(bts); - } - - /** - * Invokes the delegate's write(byte[]) method. - * @param bts the bytes to write - * @param st The start offset - * @param end The number of bytes to write - * @throws IOException if an I/O error occurs - */ - public void write(byte[] bts, int st, int end) throws IOException { - out.write(bts, st, end); - } - - /** - * Invokes the delegate's flush() method. - * @throws IOException if an I/O error occurs - */ - public void flush() throws IOException { - out.flush(); - } - - /** - * Invokes the delegate's close() method. - * @throws IOException if an I/O error occurs - */ - public void close() throws IOException { - out.close(); - } - -} diff --git a/src/org/apache/commons/io/output/ProxyWriter.java b/src/org/apache/commons/io/output/ProxyWriter.java deleted file mode 100644 index fbec62885..000000000 --- a/src/org/apache/commons/io/output/ProxyWriter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.FilterWriter; -import java.io.IOException; -import java.io.Writer; - -/** - * A Proxy stream which acts as expected, that is it passes the method - * calls on to the proxied stream and doesn't change which methods are - * being called. It is an alternative base class to FilterWriter - * to increase reusability, because FilterWriter changes the - * methods being called, such as write(char[]) to write(char[], int, int) - * and write(String) to write(String, int, int). - * - * @author Stephen Colebourne - * @version $Id: ProxyWriter.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public class ProxyWriter extends FilterWriter { - - /** - * Constructs a new ProxyWriter. - * - * @param proxy the Writer to delegate to - */ - public ProxyWriter(Writer proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'out' - } - - /** - * Invokes the delegate's write(int) method. - * @param idx the character to write - * @throws IOException if an I/O error occurs - */ - public void write(int idx) throws IOException { - out.write(idx); - } - - /** - * Invokes the delegate's write(char[]) method. - * @param chr the characters to write - * @throws IOException if an I/O error occurs - */ - public void write(char[] chr) throws IOException { - out.write(chr); - } - - /** - * Invokes the delegate's write(char[], int, int) method. - * @param chr the characters to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs - */ - public void write(char[] chr, int st, int end) throws IOException { - out.write(chr, st, end); - } - - /** - * Invokes the delegate's write(String) method. - * @param str the string to write - * @throws IOException if an I/O error occurs - */ - public void write(String str) throws IOException { - out.write(str); - } - - /** - * Invokes the delegate's write(String) method. - * @param str the string to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs - */ - public void write(String str, int st, int end) throws IOException { - out.write(str, st, end); - } - - /** - * Invokes the delegate's flush() method. - * @throws IOException if an I/O error occurs - */ - public void flush() throws IOException { - out.flush(); - } - - /** - * Invokes the delegate's close() method. - * @throws IOException if an I/O error occurs - */ - public void close() throws IOException { - out.close(); - } - -} diff --git a/src/org/apache/commons/io/output/TeeOutputStream.java b/src/org/apache/commons/io/output/TeeOutputStream.java deleted file mode 100644 index ee957fb3b..000000000 --- a/src/org/apache/commons/io/output/TeeOutputStream.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Classic splitter of OutputStream. Named after the unix 'tee' - * command. It allows a stream to be branched off so there - * are now two streams. - * - * @version $Id: TeeOutputStream.java 610010 2008-01-08 14:50:59Z niallp $ - */ -public class TeeOutputStream extends ProxyOutputStream { - - /** the second OutputStream to write to */ - protected OutputStream branch; - - /** - * Constructs a TeeOutputStream. - * @param out the main OutputStream - * @param branch the second OutputStream - */ - public TeeOutputStream( OutputStream out, OutputStream branch ) { - super(out); - this.branch = branch; - } - - /** - * Write the bytes to both streams. - * @param b the bytes to write - * @throws IOException if an I/O error occurs - */ - public synchronized void write(byte[] b) throws IOException { - super.write(b); - this.branch.write(b); - } - - /** - * Write the specified bytes to both streams. - * @param b the bytes to write - * @param off The start offset - * @param len The number of bytes to write - * @throws IOException if an I/O error occurs - */ - public synchronized void write(byte[] b, int off, int len) throws IOException { - super.write(b, off, len); - this.branch.write(b, off, len); - } - - /** - * Write a byte to both streams. - * @param b the byte to write - * @throws IOException if an I/O error occurs - */ - public synchronized void write(int b) throws IOException { - super.write(b); - this.branch.write(b); - } - - /** - * Flushes both streams. - * @throws IOException if an I/O error occurs - */ - public void flush() throws IOException { - super.flush(); - this.branch.flush(); - } - - /** - * Closes both streams. - * @throws IOException if an I/O error occurs - */ - public void close() throws IOException { - super.close(); - this.branch.close(); - } - -} diff --git a/src/org/apache/commons/io/output/ThresholdingOutputStream.java b/src/org/apache/commons/io/output/ThresholdingOutputStream.java deleted file mode 100644 index fa69a804c..000000000 --- a/src/org/apache/commons/io/output/ThresholdingOutputStream.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - - -/** - * An output stream which triggers an event when a specified number of bytes of - * data have been written to it. The event can be used, for example, to throw - * an exception if a maximum has been reached, or to switch the underlying - * stream type when the threshold is exceeded. - *

- * This class overrides all OutputStream methods. However, these - * overrides ultimately call the corresponding methods in the underlying output - * stream implementation. - *

- * NOTE: This implementation may trigger the event before the threshold - * is actually reached, since it triggers when a pending write operation would - * cause the threshold to be exceeded. - * - * @author Martin Cooper - * - * @version $Id: ThresholdingOutputStream.java 540714 2007-05-22 19:39:44Z niallp $ - */ -public abstract class ThresholdingOutputStream - extends OutputStream -{ - - // ----------------------------------------------------------- Data members - - - /** - * The threshold at which the event will be triggered. - */ - private int threshold; - - - /** - * The number of bytes written to the output stream. - */ - private long written; - - - /** - * Whether or not the configured threshold has been exceeded. - */ - private boolean thresholdExceeded; - - - // ----------------------------------------------------------- Constructors - - - /** - * Constructs an instance of this class which will trigger an event at the - * specified threshold. - * - * @param threshold The number of bytes at which to trigger an event. - */ - public ThresholdingOutputStream(int threshold) - { - this.threshold = threshold; - } - - - // --------------------------------------------------- OutputStream methods - - - /** - * Writes the specified byte to this output stream. - * - * @param b The byte to be written. - * - * @exception IOException if an error occurs. - */ - public void write(int b) throws IOException - { - checkThreshold(1); - getStream().write(b); - written++; - } - - - /** - * Writes b.length bytes from the specified byte array to this - * output stream. - * - * @param b The array of bytes to be written. - * - * @exception IOException if an error occurs. - */ - public void write(byte b[]) throws IOException - { - checkThreshold(b.length); - getStream().write(b); - written += b.length; - } - - - /** - * Writes len bytes from the specified byte array starting at - * offset off to this output stream. - * - * @param b The byte array from which the data will be written. - * @param off The start offset in the byte array. - * @param len The number of bytes to write. - * - * @exception IOException if an error occurs. - */ - public void write(byte b[], int off, int len) throws IOException - { - checkThreshold(len); - getStream().write(b, off, len); - written += len; - } - - - /** - * Flushes this output stream and forces any buffered output bytes to be - * written out. - * - * @exception IOException if an error occurs. - */ - public void flush() throws IOException - { - getStream().flush(); - } - - - /** - * Closes this output stream and releases any system resources associated - * with this stream. - * - * @exception IOException if an error occurs. - */ - public void close() throws IOException - { - try - { - flush(); - } - catch (IOException ignored) - { - // ignore - } - getStream().close(); - } - - - // --------------------------------------------------------- Public methods - - - /** - * Returns the threshold, in bytes, at which an event will be triggered. - * - * @return The threshold point, in bytes. - */ - public int getThreshold() - { - return threshold; - } - - - /** - * Returns the number of bytes that have been written to this output stream. - * - * @return The number of bytes written. - */ - public long getByteCount() - { - return written; - } - - - /** - * Determines whether or not the configured threshold has been exceeded for - * this output stream. - * - * @return true if the threshold has been reached; - * false otherwise. - */ - public boolean isThresholdExceeded() - { - return (written > threshold); - } - - - // ------------------------------------------------------ Protected methods - - - /** - * Checks to see if writing the specified number of bytes would cause the - * configured threshold to be exceeded. If so, triggers an event to allow - * a concrete implementation to take action on this. - * - * @param count The number of bytes about to be written to the underlying - * output stream. - * - * @exception IOException if an error occurs. - */ - protected void checkThreshold(int count) throws IOException - { - if (!thresholdExceeded && (written + count > threshold)) - { - thresholdExceeded = true; - thresholdReached(); - } - } - - /** - * Resets the byteCount to zero. You can call this from - * {@link #thresholdReached()} if you want the event to be triggered again. - */ - protected void resetByteCount() - { - this.thresholdExceeded = false; - this.written = 0; - } - - // ------------------------------------------------------- Abstract methods - - - /** - * Returns the underlying output stream, to which the corresponding - * OutputStream methods in this class will ultimately delegate. - * - * @return The underlying output stream. - * - * @exception IOException if an error occurs. - */ - protected abstract OutputStream getStream() throws IOException; - - - /** - * Indicates that the configured threshold has been reached, and that a - * subclass should take whatever action necessary on this event. This may - * include changing the underlying output stream. - * - * @exception IOException if an error occurs. - */ - protected abstract void thresholdReached() throws IOException; -} diff --git a/src/org/apache/commons/io/output/package.html b/src/org/apache/commons/io/output/package.html deleted file mode 100644 index db2cbce59..000000000 --- a/src/org/apache/commons/io/output/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - -

-This package provides implementations of output classes, such as -OutputStream and Writer. -

- - diff --git a/src/org/apache/commons/io/overview.html b/src/org/apache/commons/io/overview.html deleted file mode 100644 index 31311b5e9..000000000 --- a/src/org/apache/commons/io/overview.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - -

-The commons-io component contains utility classes, -filters, streams, readers and writers. -

-

-These classes aim to add to the standard JDK IO classes. -The utilities provide convenience wrappers around the JDK, simplifying -various operations into pre-tested units of code. -The filters and streams provide useful implementations that perhaps should -be in the JDK itself. -

- - diff --git a/src/org/apache/commons/io/package.html b/src/org/apache/commons/io/package.html deleted file mode 100644 index e5ba9b0aa..000000000 --- a/src/org/apache/commons/io/package.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - -

-This package defines utility classes for working with streams, readers, -writers and files. The most commonly used classes are described here: -

-

-IOUtils is the most frequently used class. -It provides operations to read, write, copy and close streams. -

-

-FileUtils provides operations based around the JDK File class. -These include reading, writing, copying, comparing and deleting. -

-

-FilenameUtils provides utilities based on filenames. -This utility class manipulates filenames without using File objects. -It aims to simplify the transition between Windows and Unix. -Before using this class however, you should consider whether you should -be using File objects. -

-

-FileSystemUtils allows access to the filing system in ways the JDK -does not support. At present this allows you to get the free space on a drive. -

-

-EndianUtils swaps data between Big-Endian and Little-Endian formats. -

- - diff --git a/src/org/apache/james/mime4j/AbstractContentHandler.java b/src/org/apache/james/mime4j/AbstractContentHandler.java deleted file mode 100644 index 06c9b90a0..000000000 --- a/src/org/apache/james/mime4j/AbstractContentHandler.java +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Abstract ContentHandler with default implementations of all - * the methods of the ContentHandler interface. - * - * The default is to todo nothing. - * - * - * @version $Id: AbstractContentHandler.java,v 1.3 2004/10/02 12:41:10 ntherning Exp $ - */ -public abstract class AbstractContentHandler implements ContentHandler { - - /** - * @see org.apache.james.mime4j.ContentHandler#endMultipart() - */ - public void endMultipart() { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startMultipart(org.apache.james.mime4j.BodyDescriptor) - */ - public void startMultipart(BodyDescriptor bd) { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream) - */ - public void body(BodyDescriptor bd, InputStream is) throws IOException { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#endBodyPart() - */ - public void endBodyPart() { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#endHeader() - */ - public void endHeader() { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#endMessage() - */ - public void endMessage() { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#epilogue(java.io.InputStream) - */ - public void epilogue(InputStream is) throws IOException { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#field(java.lang.String) - */ - public void field(String fieldData) { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#preamble(java.io.InputStream) - */ - public void preamble(InputStream is) throws IOException { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startBodyPart() - */ - public void startBodyPart() { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startHeader() - */ - public void startHeader() { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startMessage() - */ - public void startMessage() { - } - - /** - * @see org.apache.james.mime4j.ContentHandler#raw(java.io.InputStream) - */ - public void raw(InputStream is) throws IOException { - } -} diff --git a/src/org/apache/james/mime4j/BodyDescriptor.java b/src/org/apache/james/mime4j/BodyDescriptor.java deleted file mode 100644 index 515658a8d..000000000 --- a/src/org/apache/james/mime4j/BodyDescriptor.java +++ /dev/null @@ -1,410 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Encapsulates the values of the MIME-specific header fields - * (which starts with Content-). - * - * - * @version $Id: BodyDescriptor.java,v 1.4 2005/02/11 10:08:37 ntherning Exp $ - */ -public class BodyDescriptor { - private static Log log = LogFactory.getLog(BodyDescriptor.class); - - private String mimeType = "text/plain"; - private String boundary = null; - private String charset = "us-ascii"; - private String transferEncoding = "7bit"; - private Map parameters = new HashMap(); - private boolean contentTypeSet = false; - private boolean contentTransferEncSet = false; - - /** - * Creates a new root BodyDescriptor instance. - */ - public BodyDescriptor() { - this(null); - } - - /** - * Creates a new BodyDescriptor instance. - * - * @param parent the descriptor of the parent or null if this - * is the root descriptor. - */ - public BodyDescriptor(BodyDescriptor parent) { - if (parent != null && parent.isMimeType("multipart/digest")) { - mimeType = "message/rfc822"; - } else { - mimeType = "text/plain"; - } - } - - /** - * Should be called for each Content- header field of - * a MIME message or part. - * - * @param name the field name. - * @param value the field value. - */ - public void addField(String name, String value) { - - name = name.trim().toLowerCase(); - - if (name.equals("content-transfer-encoding") && !contentTransferEncSet) { - contentTransferEncSet = true; - - value = value.trim().toLowerCase(); - if (value.length() > 0) { - transferEncoding = value; - } - - } else if (name.equals("content-type") && !contentTypeSet) { - contentTypeSet = true; - - value = value.trim(); - - /* - * Unfold Content-Type value - */ - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < value.length(); i++) { - char c = value.charAt(i); - if (c == '\r' || c == '\n') { - continue; - } - sb.append(c); - } - - Map params = getHeaderParams(sb.toString()); - - String main = (String) params.get(""); - if (main != null) { - main = main.toLowerCase().trim(); - int index = main.indexOf('/'); - boolean valid = false; - if (index != -1) { - String type = main.substring(0, index).trim(); - String subtype = main.substring(index + 1).trim(); - if (type.length() > 0 && subtype.length() > 0) { - main = type + "/" + subtype; - valid = true; - } - } - - if (!valid) { - main = null; - } - } - String b = (String) params.get("boundary"); - - if (main != null - && ((main.startsWith("multipart/") && b != null) - || !main.startsWith("multipart/"))) { - - mimeType = main; - } - - if (isMultipart()) { - boundary = b; - } - - String c = (String) params.get("charset"); - if (c != null) { - c = c.trim(); - if (c.length() > 0) { - charset = c.toLowerCase(); - } - } - - /* - * Add all other parameters to parameters. - */ - parameters.putAll(params); - parameters.remove(""); - parameters.remove("boundary"); - parameters.remove("charset"); - } - } - - private Map getHeaderParams(String headerValue) { - Map result = new HashMap(); - - // split main value and parameters - String main; - String rest; - if (headerValue.indexOf(";") == -1) { - main = headerValue; - rest = null; - } else { - main = headerValue.substring(0, headerValue.indexOf(";")); - rest = headerValue.substring(main.length() + 1); - } - - result.put("", main); - if (rest != null) { - char[] chars = rest.toCharArray(); - StringBuffer paramName = new StringBuffer(); - StringBuffer paramValue = new StringBuffer(); - - final byte READY_FOR_NAME = 0; - final byte IN_NAME = 1; - final byte READY_FOR_VALUE = 2; - final byte IN_VALUE = 3; - final byte IN_QUOTED_VALUE = 4; - final byte VALUE_DONE = 5; - final byte ERROR = 99; - - byte state = READY_FOR_NAME; - boolean escaped = false; - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - - switch (state) { - case ERROR: - if (c == ';') - state = READY_FOR_NAME; - break; - - case READY_FOR_NAME: - if (c == '=') { - log.error("Expected header param name, got '='"); - state = ERROR; - break; - } - - paramName = new StringBuffer(); - paramValue = new StringBuffer(); - - state = IN_NAME; - // fall-through - - case IN_NAME: - if (c == '=') { - if (paramName.length() == 0) - state = ERROR; - else - state = READY_FOR_VALUE; - break; - } - - // not '='... just add to name - paramName.append(c); - break; - - case READY_FOR_VALUE: - boolean fallThrough = false; - switch (c) { - case ' ': - case '\t': - break; // ignore spaces, especially before '"' - - case '"': - state = IN_QUOTED_VALUE; - break; - - default: - state = IN_VALUE; - fallThrough = true; - break; - } - if (!fallThrough) - break; - - // fall-through - - case IN_VALUE: - fallThrough = false; - switch (c) { - case ';': - case ' ': - case '\t': - result.put( - paramName.toString().trim().toLowerCase(), - paramValue.toString().trim()); - state = VALUE_DONE; - fallThrough = true; - break; - default: - paramValue.append(c); - break; - } - if (!fallThrough) - break; - - case VALUE_DONE: - switch (c) { - case ';': - state = READY_FOR_NAME; - break; - - case ' ': - case '\t': - break; - - default: - state = ERROR; - break; - } - break; - - case IN_QUOTED_VALUE: - switch (c) { - case '"': - if (!escaped) { - // don't trim quoted strings; the spaces could be intentional. - result.put( - paramName.toString().trim().toLowerCase(), - paramValue.toString()); - state = VALUE_DONE; - } else { - escaped = false; - paramValue.append(c); - } - break; - - case '\\': - if (escaped) { - paramValue.append('\\'); - } - escaped = !escaped; - break; - - default: - if (escaped) { - paramValue.append('\\'); - } - escaped = false; - paramValue.append(c); - break; - } - break; - - } - } - - // done looping. check if anything is left over. - if (state == IN_VALUE) { - result.put( - paramName.toString().trim().toLowerCase(), - paramValue.toString().trim()); - } - } - - return result; - } - - - public boolean isMimeType(String mimeType) { - return this.mimeType.equals(mimeType.toLowerCase()); - } - - /** - * Return true if the BodyDescriptor belongs to a message - * - * @return - */ - public boolean isMessage() { - return mimeType.equals("message/rfc822"); - } - - /** - * Retrun true if the BodyDescripotro belogns to a multipart - * - * @return - */ - public boolean isMultipart() { - return mimeType.startsWith("multipart/"); - } - - /** - * Return the MimeType - * - * @return mimeType - */ - public String getMimeType() { - return mimeType; - } - - /** - * Return the boundary - * - * @return boundary - */ - public String getBoundary() { - return boundary; - } - - /** - * Return the charset - * - * @return charset - */ - public String getCharset() { - return charset; - } - - /** - * Return all parameters for the BodyDescriptor - * - * @return parameters - */ - public Map getParameters() { - return parameters; - } - - /** - * Return the TransferEncoding - * - * @return transferEncoding - */ - public String getTransferEncoding() { - return transferEncoding; - } - - /** - * Return true if it's base64 encoded - * - * @return - * - */ - public boolean isBase64Encoded() { - return "base64".equals(transferEncoding); - } - - /** - * Return true if it's quoted-printable - * @return - */ - public boolean isQuotedPrintableEncoded() { - return "quoted-printable".equals(transferEncoding); - } - - public String toString() { - return mimeType; - } -} diff --git a/src/org/apache/james/mime4j/CloseShieldInputStream.java b/src/org/apache/james/mime4j/CloseShieldInputStream.java deleted file mode 100644 index 94995d110..000000000 --- a/src/org/apache/james/mime4j/CloseShieldInputStream.java +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.InputStream; -import java.io.IOException; - -/** - * InputStream that shields its underlying input stream from - * being closed. - * - * - * @version $Id: CloseShieldInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $ - */ -public class CloseShieldInputStream extends InputStream { - - /** - * Underlying InputStream - */ - private InputStream is; - - public CloseShieldInputStream(InputStream is) { - this.is = is; - } - - public InputStream getUnderlyingStream() { - return is; - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - checkIfClosed(); - return is.read(); - } - - /** - * @see java.io.InputStream#available() - */ - public int available() throws IOException { - checkIfClosed(); - return is.available(); - } - - - /** - * Set the underlying InputStream to null - */ - public void close() throws IOException { - is = null; - } - - /** - * @see java.io.FilterInputStream#reset() - */ - public synchronized void reset() throws IOException { - checkIfClosed(); - is.reset(); - } - - /** - * @see java.io.FilterInputStream#markSupported() - */ - public boolean markSupported() { - if (is == null) - return false; - return is.markSupported(); - } - - /** - * @see java.io.FilterInputStream#mark(int) - */ - public synchronized void mark(int readlimit) { - if (is != null) - is.mark(readlimit); - } - - /** - * @see java.io.FilterInputStream#skip(long) - */ - public long skip(long n) throws IOException { - checkIfClosed(); - return is.skip(n); - } - - /** - * @see java.io.FilterInputStream#read(byte[]) - */ - public int read(byte b[]) throws IOException { - checkIfClosed(); - return is.read(b); - } - - /** - * @see java.io.FilterInputStream#read(byte[], int, int) - */ - public int read(byte b[], int off, int len) throws IOException { - checkIfClosed(); - return is.read(b, off, len); - } - - /** - * Check if the underlying InputStream is null. If so throw an Exception - * - * @throws IOException if the underlying InputStream is null - */ - private void checkIfClosed() throws IOException { - if (is == null) - throw new IOException("Stream is closed"); - } -} diff --git a/src/org/apache/james/mime4j/ContentHandler.java b/src/org/apache/james/mime4j/ContentHandler.java deleted file mode 100644 index 946c89401..000000000 --- a/src/org/apache/james/mime4j/ContentHandler.java +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; - -/** - *

- * Receives notifications of the content of a plain RFC822 or MIME message. - * Implement this interface and register an instance of that implementation - * with a MimeStreamParser instance using its - * {@link org.apache.james.mime4j.MimeStreamParser#setContentHandler(ContentHandler)} - * method. The parser uses the ContentHandler instance to report - * basic message-related events like the start and end of the body of a - * part in a multipart MIME entity. - *

- *

- * Events will be generated in the order the corresponding elements occur in - * the message stream parsed by the parser. E.g.: - *

- *      startMessage()
- *          startHeader()
- *              field(...)
- *              field(...)
- *              ...
- *          endHeader()
- *          startMultipart()
- *              preamble(...)
- *              startBodyPart()
- *                  startHeader()
- *                      field(...)
- *                      field(...)
- *                      ...
- *                  endHeader()
- *                  body()
- *              endBodyPart()
- *              startBodyPart()
- *                  startHeader()
- *                      field(...)
- *                      field(...)
- *                      ...
- *                  endHeader()
- *                  body()
- *              endBodyPart()
- *              epilogue(...)
- *          endMultipart()
- *      endMessage()
- * 
- * The above shows an example of a MIME message consisting of a multipart - * body containing two body parts. - *

- *

- * See MIME RFCs 2045-2049 for more information on the structure of MIME - * messages and RFC 822 and 2822 for the general structure of Internet mail - * messages. - *

- * - * - * @version $Id: ContentHandler.java,v 1.3 2004/10/02 12:41:10 ntherning Exp $ - */ -public interface ContentHandler { - /** - * Called when a new message starts (a top level message or an embedded - * rfc822 message). - */ - void startMessage(); - - /** - * Called when a message ends. - */ - void endMessage(); - - /** - * Called when a new body part starts inside a - * multipart/* entity. - */ - void startBodyPart(); - - /** - * Called when a body part ends. - */ - void endBodyPart(); - - /** - * Called when a header (of a message or body part) is about to be parsed. - */ - void startHeader(); - - /** - * Called for each field of a header. - * - * @param fieldData the raw contents of the field - * (Field-Name: field value). The value will not be - * unfolded. - */ - void field(String fieldData); - - /** - * Called when there are no more header fields in a message or body part. - */ - void endHeader(); - - /** - * Called for the preamble (whatever comes before the first body part) - * of a multipart/* entity. - * - * @param is used to get the contents of the preamble. - * @throws IOException should be thrown on I/O errors. - */ - void preamble(InputStream is) throws IOException; - - /** - * Called for the epilogue (whatever comes after the final body part) - * of a multipart/* entity. - * - * @param is used to get the contents of the epilogue. - * @throws IOException should be thrown on I/O errors. - */ - void epilogue(InputStream is) throws IOException; - - /** - * Called when the body of a multipart entity is about to be parsed. - * - * @param bd encapsulates the values (either read from the - * message stream or, if not present, determined implictly - * as described in the - * MIME rfc:s) of the Content-Type and - * Content-Transfer-Encoding header fields. - */ - void startMultipart(BodyDescriptor bd); - - /** - * Called when the body of an entity has been parsed. - */ - void endMultipart(); - - /** - * Called when the body of a discrete (non-multipart) entity is about to - * be parsed. - * - * @param bd see {@link #startMultipart(BodyDescriptor)} - * @param is the contents of the body. NOTE: this is the raw body contents - * - it will not be decoded if encoded. The bd - * parameter should be used to determine how the stream data - * should be decoded. - * @throws IOException should be thrown on I/O errors. - */ - void body(BodyDescriptor bd, InputStream is) throws IOException; - - /** - * Called when a new entity (message or body part) starts and the - * parser is in raw mode. - * - * @param is the raw contents of the entity. - * @throws IOException should be thrown on I/O errors. - * @see MimeStreamParser#setRaw(boolean) - */ - void raw(InputStream is) throws IOException; -} diff --git a/src/org/apache/james/mime4j/EOLConvertingInputStream.java b/src/org/apache/james/mime4j/EOLConvertingInputStream.java deleted file mode 100644 index 7d5009ca5..000000000 --- a/src/org/apache/james/mime4j/EOLConvertingInputStream.java +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; - -/** - * InputStream which converts \r - * bytes not followed by \n and \n not - * preceded by \r to \r\n. - * - * - * @version $Id: EOLConvertingInputStream.java,v 1.4 2004/11/29 13:15:42 ntherning Exp $ - */ -public class EOLConvertingInputStream extends InputStream { - /** Converts single '\r' to '\r\n' */ - public static final int CONVERT_CR = 1; - /** Converts single '\n' to '\r\n' */ - public static final int CONVERT_LF = 2; - /** Converts single '\r' and '\n' to '\r\n' */ - public static final int CONVERT_BOTH = 3; - - private PushbackInputStream in = null; - private int previous = 0; - private int flags = CONVERT_BOTH; - - /** - * Creates a new EOLConvertingInputStream - * instance converting bytes in the given InputStream. - * The flag CONVERT_BOTH is the default. - * - * @param in the InputStream to read from. - */ - public EOLConvertingInputStream(InputStream in) { - this(in, CONVERT_BOTH); - } - /** - * Creates a new EOLConvertingInputStream - * instance converting bytes in the given InputStream. - * - * @param in the InputStream to read from. - * @param flags one of CONVERT_CR, CONVERT_LF or - * CONVERT_BOTH. - */ - public EOLConvertingInputStream(InputStream in, int flags) { - super(); - - this.in = new PushbackInputStream(in, 2); - this.flags = flags; - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - public void close() throws IOException { - in.close(); - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - int b = in.read(); - - if (b == -1) { - return -1; - } - - if ((flags & CONVERT_CR) != 0 && b == '\r') { - int c = in.read(); - if (c != -1) { - in.unread(c); - } - if (c != '\n') { - in.unread('\n'); - } - } else if ((flags & CONVERT_LF) != 0 && b == '\n' && previous != '\r') { - b = '\r'; - in.unread('\n'); - } - - previous = b; - - return b; - } - -} diff --git a/src/org/apache/james/mime4j/MimeBoundaryInputStream.java b/src/org/apache/james/mime4j/MimeBoundaryInputStream.java deleted file mode 100644 index 0fffb7820..000000000 --- a/src/org/apache/james/mime4j/MimeBoundaryInputStream.java +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; - -/** - * Stream that constrains itself to a single MIME body part. - * After the stream ends (i.e. read() returns -1) {@link #hasMoreParts()} - * can be used to determine if a final boundary has been seen or not. - * If {@link #parentEOF()} is true an unexpected end of stream - * has been detected in the parent stream. - * - * - * - * @version $Id: MimeBoundaryInputStream.java,v 1.2 2004/11/29 13:15:42 ntherning Exp $ - */ -public class MimeBoundaryInputStream extends InputStream { - - private PushbackInputStream s = null; - private byte[] boundary = null; - private boolean first = true; - private boolean eof = false; - private boolean parenteof = false; - private boolean moreParts = true; - - /** - * Creates a new MimeBoundaryInputStream. - * @param s The underlying stream. - * @param boundary Boundary string (not including leading hyphens). - */ - public MimeBoundaryInputStream(InputStream s, String boundary) - throws IOException { - - this.s = new PushbackInputStream(s, boundary.length() + 4); - - boundary = "--" + boundary; - this.boundary = new byte[boundary.length()]; - for (int i = 0; i < this.boundary.length; i++) { - this.boundary[i] = (byte) boundary.charAt(i); - } - - /* - * By reading one byte we will update moreParts to be as expected - * before any bytes have been read. - */ - int b = read(); - if (b != -1) { - this.s.unread(b); - } - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - public void close() throws IOException { - s.close(); - } - - /** - * Determines if the underlying stream has more parts (this stream has - * not seen an end boundary). - * - * @return true if there are more parts in the underlying - * stream, false otherwise. - */ - public boolean hasMoreParts() { - return moreParts; - } - - /** - * Determines if the parent stream has reached EOF - * - * @return true if EOF has been reached for the parent stream, - * false otherwise. - */ - public boolean parentEOF() { - return parenteof; - } - - /** - * Consumes all unread bytes of this stream. After a call to this method - * this stream will have reached EOF. - * - * @throws IOException on I/O errors. - */ - public void consume() throws IOException { - while (read() != -1) { - } - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - if (eof) { - return -1; - } - - if (first) { - first = false; - if (matchBoundary()) { - return -1; - } - } - - int b1 = s.read(); - int b2 = s.read(); - - if (b1 == '\r' && b2 == '\n') { - if (matchBoundary()) { - return -1; - } - } - - if (b2 != -1) { - s.unread(b2); - } - - parenteof = b1 == -1; - eof = parenteof; - - return b1; - } - - private boolean matchBoundary() throws IOException { - - for (int i = 0; i < boundary.length; i++) { - int b = s.read(); - if (b != boundary[i]) { - if (b != -1) { - s.unread(b); - } - for (int j = i - 1; j >= 0; j--) { - s.unread(boundary[j]); - } - return false; - } - } - - /* - * We have a match. Is it an end boundary? - */ - int prev = s.read(); - int curr = s.read(); - moreParts = !(prev == '-' && curr == '-'); - do { - if (curr == '\n' && prev == '\r') { - break; - } - prev = curr; - } while ((curr = s.read()) != -1); - - if (curr == -1) { - moreParts = false; - parenteof = true; - } - - eof = true; - - return true; - } -} diff --git a/src/org/apache/james/mime4j/MimeStreamParser.java b/src/org/apache/james/mime4j/MimeStreamParser.java deleted file mode 100644 index 2e486adc3..000000000 --- a/src/org/apache/james/mime4j/MimeStreamParser.java +++ /dev/null @@ -1,320 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; -import java.util.BitSet; -import java.util.LinkedList; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.decoder.Base64InputStream; -import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; - -/** - *

- * Parses MIME (or RFC822) message streams of bytes or characters and reports - * parsing events to a ContentHandler instance. - *

- *

- * Typical usage:
- *

- *      ContentHandler handler = new MyHandler();
- *      MimeStreamParser parser = new MimeStreamParser();
- *      parser.setContentHandler(handler);
- *      parser.parse(new BufferedInputStream(new FileInputStream("mime.msg")));
- * 
- * NOTE: All lines must end with CRLF - * (\r\n). If you are unsure of the line endings in your stream - * you should wrap it in a {@link org.apache.james.mime4j.EOLConvertingInputStream} instance. - * - * - * @version $Id: MimeStreamParser.java,v 1.8 2005/02/11 10:12:02 ntherning Exp $ - */ -public class MimeStreamParser { - private static final Log log = LogFactory.getLog(MimeStreamParser.class); - - private static BitSet fieldChars = null; - - private RootInputStream rootStream = null; - private LinkedList bodyDescriptors = new LinkedList(); - private ContentHandler handler = null; - private boolean raw = false; - - static { - fieldChars = new BitSet(); - for (int i = 0x21; i <= 0x39; i++) { - fieldChars.set(i); - } - for (int i = 0x3b; i <= 0x7e; i++) { - fieldChars.set(i); - } - } - - /** - * Creates a new MimeStreamParser instance. - */ - public MimeStreamParser() { - } - - /** - * Parses a stream of bytes containing a MIME message. - * - * @param is the stream to parse. - * @throws IOException on I/O errors. - */ - public void parse(InputStream is) throws IOException { - rootStream = new RootInputStream(is); - parseMessage(rootStream); - } - - /** - * Determines if this parser is currently in raw mode. - * - * @return true if in raw mode, false - * otherwise. - * @see #setRaw(boolean) - */ - public boolean isRaw() { - return raw; - } - - /** - * Enables or disables raw mode. In raw mode all future entities - * (messages or body parts) in the stream will be reported to the - * {@link ContentHandler#raw(InputStream)} handler method only. - * The stream will contain the entire unparsed entity contents - * including header fields and whatever is in the body. - * - * @param raw true enables raw mode, false - * disables it. - */ - public void setRaw(boolean raw) { - this.raw = raw; - } - - /** - * Finishes the parsing and stops reading lines. - * NOTE: No more lines will be parsed but the parser - * will still call - * {@link ContentHandler#endMultipart()}, - * {@link ContentHandler#endBodyPart()}, - * {@link ContentHandler#endMessage()}, etc to match previous calls - * to - * {@link ContentHandler#startMultipart(BodyDescriptor)}, - * {@link ContentHandler#startBodyPart()}, - * {@link ContentHandler#startMessage()}, etc. - */ - public void stop() { - rootStream.truncate(); - } - - /** - * Parses an entity which consists of a header followed by a body containing - * arbitrary data, body parts or an embedded message. - * - * @param is the stream to parse. - * @throws IOException on I/O errors. - */ - private void parseEntity(InputStream is) throws IOException { - BodyDescriptor bd = parseHeader(is); - - if (bd.isMultipart()) { - bodyDescriptors.addFirst(bd); - - handler.startMultipart(bd); - - MimeBoundaryInputStream tempIs = - new MimeBoundaryInputStream(is, bd.getBoundary()); - handler.preamble(new CloseShieldInputStream(tempIs)); - tempIs.consume(); - - while (tempIs.hasMoreParts()) { - tempIs = new MimeBoundaryInputStream(is, bd.getBoundary()); - parseBodyPart(tempIs); - tempIs.consume(); - if (tempIs.parentEOF()) { - if (log.isWarnEnabled()) { - log.warn("Line " + rootStream.getLineNumber() - + ": Body part ended prematurely. " - + "Higher level boundary detected or " - + "EOF reached."); - } - break; - } - } - - handler.epilogue(new CloseShieldInputStream(is)); - - handler.endMultipart(); - - bodyDescriptors.removeFirst(); - - } else if (bd.isMessage()) { - if (bd.isBase64Encoded()) { - log.warn("base64 encoded message/rfc822 detected"); - is = new EOLConvertingInputStream( - new Base64InputStream(is)); - } else if (bd.isQuotedPrintableEncoded()) { - log.warn("quoted-printable encoded message/rfc822 detected"); - is = new EOLConvertingInputStream( - new QuotedPrintableInputStream(is)); - } - bodyDescriptors.addFirst(bd); - parseMessage(is); - bodyDescriptors.removeFirst(); - } else { - handler.body(bd, new CloseShieldInputStream(is)); - } - - /* - * Make sure the stream has been consumed. - */ - while (is.read() != -1) { - } - } - - private void parseMessage(InputStream is) throws IOException { - if (raw) { - handler.raw(new CloseShieldInputStream(is)); - } else { - handler.startMessage(); - parseEntity(is); - handler.endMessage(); - } - } - - private void parseBodyPart(InputStream is) throws IOException { - if (raw) { - handler.raw(new CloseShieldInputStream(is)); - } else { - handler.startBodyPart(); - parseEntity(is); - handler.endBodyPart(); - } - } - - /** - * Parses a header. - * - * @param is the stream to parse. - * @return a BodyDescriptor describing the body following - * the header. - */ - private BodyDescriptor parseHeader(InputStream is) throws IOException { - BodyDescriptor bd = new BodyDescriptor(bodyDescriptors.isEmpty() - ? null : (BodyDescriptor) bodyDescriptors.getFirst()); - - handler.startHeader(); - - int lineNumber = rootStream.getLineNumber(); - - StringBuffer sb = new StringBuffer(); - int curr = 0; - int prev = 0; - while ((curr = is.read()) != -1) { - if (curr == '\n' && (prev == '\n' || prev == 0)) { - /* - * [\r]\n[\r]\n or an immediate \r\n have been seen. - */ - sb.deleteCharAt(sb.length() - 1); - break; - } - sb.append((char) curr); - prev = curr == '\r' ? prev : curr; - } - - if (curr == -1 && log.isWarnEnabled()) { - log.warn("Line " + rootStream.getLineNumber() - + ": Unexpected end of headers detected. " - + "Boundary detected in header or EOF reached."); - } - - int start = 0; - int pos = 0; - int startLineNumber = lineNumber; - while (pos < sb.length()) { - while (pos < sb.length() && sb.charAt(pos) != '\r') { - pos++; - } - if (pos < sb.length() - 1 && sb.charAt(pos + 1) != '\n') { - pos++; - continue; - } - - if (pos >= sb.length() - 2 || fieldChars.get(sb.charAt(pos + 2))) { - - /* - * field should be the complete field data excluding the - * trailing \r\n. - */ - String field = sb.substring(start, pos); - start = pos + 2; - - /* - * Check for a valid field. - */ - int index = field.indexOf(':'); - boolean valid = false; - if (index != -1 && fieldChars.get(field.charAt(0))) { - valid = true; - String fieldName = field.substring(0, index).trim(); - for (int i = 0; i < fieldName.length(); i++) { - if (!fieldChars.get(fieldName.charAt(i))) { - valid = false; - break; - } - } - - if (valid) { - handler.field(field); - bd.addField(fieldName, field.substring(index + 1)); - } - } - - if (!valid && log.isWarnEnabled()) { - log.warn("Line " + startLineNumber - + ": Ignoring invalid field: '" + field.trim() + "'"); - } - - startLineNumber = lineNumber; - } - - pos += 2; - lineNumber++; - } - - handler.endHeader(); - - return bd; - } - - /** - * Sets the ContentHandler to use when reporting - * parsing events. - * - * @param h the ContentHandler. - */ - public void setContentHandler(ContentHandler h) { - this.handler = h; - } - -} diff --git a/src/org/apache/james/mime4j/RootInputStream.java b/src/org/apache/james/mime4j/RootInputStream.java deleted file mode 100644 index fa848df18..000000000 --- a/src/org/apache/james/mime4j/RootInputStream.java +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import java.io.IOException; -import java.io.InputStream; - -/** - * InputStream used by the parser to wrap the original user - * supplied stream. This stream keeps track of the current line number and - * can also be truncated. When truncated the stream will appear to have - * reached end of file. This is used by the parser's - * {@link org.apache.james.mime4j.MimeStreamParser#stop()} method. - * - * - * @version $Id: RootInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $ - */ -class RootInputStream extends InputStream { - private InputStream is = null; - private int lineNumber = 1; - private int prev = -1; - private boolean truncated = false; - - /** - * Creates a new RootInputStream. - * - * @param in the stream to read from. - */ - public RootInputStream(InputStream is) { - this.is = is; - } - - /** - * Gets the current line number starting at 1 - * (the number of \r\n read so far plus 1). - * - * @return the current line number. - */ - public int getLineNumber() { - return lineNumber; - } - - /** - * Truncates this InputStream. After this call any - * call to {@link #read()}, {@link #read(byte[]) or - * {@link #read(byte[], int, int)} will return - * -1 as if end-of-file had been reached. - */ - public void truncate() { - this.truncated = true; - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - if (truncated) { - return -1; - } - - int b = is.read(); - if (prev == '\r' && b == '\n') { - lineNumber++; - } - prev = b; - return b; - } - - /** - * - * @see java.io.InputStream#read(byte[], int, int) - */ - public int read(byte[] b, int off, int len) throws IOException { - if (truncated) { - return -1; - } - - int n = is.read(b, off, len); - for (int i = off; i < off + n; i++) { - if (prev == '\r' && b[i] == '\n') { - lineNumber++; - } - prev = b[i]; - } - return n; - } - - /** - * @see java.io.InputStream#read(byte[]) - */ - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } -} diff --git a/src/org/apache/james/mime4j/SimpleContentHandler.java b/src/org/apache/james/mime4j/SimpleContentHandler.java deleted file mode 100644 index 13f1fd2c6..000000000 --- a/src/org/apache/james/mime4j/SimpleContentHandler.java +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j; - -import org.apache.james.mime4j.decoder.Base64InputStream; -import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; -import org.apache.james.mime4j.field.Field; -import org.apache.james.mime4j.message.Header; - -import java.io.InputStream; -import java.io.IOException; - -/** - * Abstract implementation of ContentHandler that automates common - * tasks. Currently performs header parsing and applies content-transfer - * decoding to body parts. - * - * - */ -public abstract class SimpleContentHandler extends AbstractContentHandler { - - /** - * Called after headers are parsed. - */ - public abstract void headers(Header header); - - /** - * Called when the body of a discrete (non-multipart) entity is encountered. - - * @param bd encapsulates the values (either read from the - * message stream or, if not present, determined implictly - * as described in the - * MIME rfc:s) of the Content-Type and - * Content-Transfer-Encoding header fields. - * @param is the contents of the body. Base64 or quoted-printable - * decoding will be applied transparently. - * @throws IOException should be thrown on I/O errors. - */ - public abstract void bodyDecoded(BodyDescriptor bd, InputStream is) throws IOException; - - - /* Implement introduced callbacks. */ - - private Header currHeader; - - /** - * @see org.apache.james.mime4j.AbstractContentHandler#startHeader() - */ - public final void startHeader() { - currHeader = new Header(); - } - - /** - * @see org.apache.james.mime4j.AbstractContentHandler#field(java.lang.String) - */ - public final void field(String fieldData) { - currHeader.addField(Field.parse(fieldData)); - } - - /** - * @see org.apache.james.mime4j.AbstractContentHandler#endHeader() - */ - public final void endHeader() { - Header tmp = currHeader; - currHeader = null; - headers(tmp); - } - - /** - * @see org.apache.james.mime4j.AbstractContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream) - */ - public final void body(BodyDescriptor bd, InputStream is) throws IOException { - if (bd.isBase64Encoded()) { - bodyDecoded(bd, new Base64InputStream(is)); - } - else if (bd.isQuotedPrintableEncoded()) { - bodyDecoded(bd, new QuotedPrintableInputStream(is)); - } - else { - bodyDecoded(bd, is); - } - } -} diff --git a/src/org/apache/james/mime4j/decoder/Base64InputStream.java b/src/org/apache/james/mime4j/decoder/Base64InputStream.java deleted file mode 100644 index 930b982c4..000000000 --- a/src/org/apache/james/mime4j/decoder/Base64InputStream.java +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Performs Base-64 decoding on an underlying stream. - * - * - * @version $Id: Base64InputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $ - */ -public class Base64InputStream extends InputStream { - private static Log log = LogFactory.getLog(Base64InputStream.class); - - private final InputStream s; - private final ByteQueue byteq = new ByteQueue(3); - private boolean done = false; - - public Base64InputStream(InputStream s) { - this.s = s; - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - public void close() throws IOException { - s.close(); - } - - public int read() throws IOException { - if (byteq.count() == 0) { - fillBuffer(); - if (byteq.count() == 0) { - return -1; - } - } - - byte val = byteq.dequeue(); - if (val >= 0) - return val; - else - return val & 0xFF; - } - - /** - * Retrieve data from the underlying stream, decode it, - * and put the results in the byteq. - * @throws IOException - */ - private void fillBuffer() throws IOException { - byte[] data = new byte[4]; - int pos = 0; - - int i; - while (!done) { - switch (i = s.read()) { - case -1: - if (pos > 0) { - log.warn("Unexpected EOF in MIME parser, dropping " - + pos + " sextets"); - } - return; - case '=': - decodeAndEnqueue(data, pos); - done = true; - break; - default: - byte sX = TRANSLATION[i]; - if (sX < 0) - continue; - data[pos++] = sX; - if (pos == data.length) { - decodeAndEnqueue(data, pos); - return; - } - break; - } - } - } - - private void decodeAndEnqueue(byte[] data, int len) { - int accum = 0; - accum |= data[0] << 18; - accum |= data[1] << 12; - accum |= data[2] << 6; - accum |= data[3]; - - byte b1 = (byte)(accum >>> 16); - byteq.enqueue(b1); - - if (len > 2) { - byte b2 = (byte)((accum >>> 8) & 0xFF); - byteq.enqueue(b2); - - if (len > 3) { - byte b3 = (byte)(accum & 0xFF); - byteq.enqueue(b3); - } - } - } - - private static byte[] TRANSLATION = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */ - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */ - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xF0 */ - }; - - -} diff --git a/src/org/apache/james/mime4j/decoder/ByteQueue.java b/src/org/apache/james/mime4j/decoder/ByteQueue.java deleted file mode 100644 index 68e7d3380..000000000 --- a/src/org/apache/james/mime4j/decoder/ByteQueue.java +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.util.Iterator; - -public class ByteQueue { - - private UnboundedFifoByteBuffer buf; - private int initialCapacity = -1; - - public ByteQueue() { - buf = new UnboundedFifoByteBuffer(); - } - - public ByteQueue(int initialCapacity) { - buf = new UnboundedFifoByteBuffer(initialCapacity); - this.initialCapacity = initialCapacity; - } - - public void enqueue(byte b) { - buf.add(b); - } - - public byte dequeue() { - return buf.remove(); - } - - public int count() { - return buf.size(); - } - - public void clear() { - if (initialCapacity != -1) - buf = new UnboundedFifoByteBuffer(initialCapacity); - else - buf = new UnboundedFifoByteBuffer(); - } - - public Iterator iterator() { - return buf.iterator(); - } - - -} diff --git a/src/org/apache/james/mime4j/decoder/DecoderUtil.java b/src/org/apache/james/mime4j/decoder/DecoderUtil.java deleted file mode 100644 index 9bd2c512d..000000000 --- a/src/org/apache/james/mime4j/decoder/DecoderUtil.java +++ /dev/null @@ -1,276 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.util.CharsetUtil; - -/** - * Static methods for decoding strings, byte arrays and encoded words. - * - * - * @version $Id: DecoderUtil.java,v 1.3 2005/02/07 15:33:59 ntherning Exp $ - */ -public class DecoderUtil { - private static Log log = LogFactory.getLog(DecoderUtil.class); - - /** - * Decodes a string containing quoted-printable encoded data. - * - * @param s the string to decode. - * @return the decoded bytes. - */ - public static byte[] decodeBaseQuotedPrintable(String s) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - try { - byte[] bytes = s.getBytes("US-ASCII"); - - QuotedPrintableInputStream is = new QuotedPrintableInputStream( - new ByteArrayInputStream(bytes)); - - int b = 0; - while ((b = is.read()) != -1) { - baos.write(b); - } - } catch (IOException e) { - /* - * This should never happen! - */ - log.error(e); - } - - return baos.toByteArray(); - } - - /** - * Decodes a string containing base64 encoded data. - * - * @param s the string to decode. - * @return the decoded bytes. - */ - public static byte[] decodeBase64(String s) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - try { - byte[] bytes = s.getBytes("US-ASCII"); - - Base64InputStream is = new Base64InputStream( - new ByteArrayInputStream(bytes)); - - int b = 0; - while ((b = is.read()) != -1) { - baos.write(b); - } - } catch (IOException e) { - /* - * This should never happen! - */ - log.error(e); - } - - return baos.toByteArray(); - } - - /** - * Decodes an encoded word encoded with the 'B' encoding (described in - * RFC 2047) found in a header field body. - * - * @param encodedWord the encoded word to decode. - * @param charset the Java charset to use. - * @return the decoded string. - * @throws UnsupportedEncodingException if the given Java charset isn't - * supported. - */ - public static String decodeB(String encodedWord, String charset) - throws UnsupportedEncodingException { - - return new String(decodeBase64(encodedWord), charset); - } - - /** - * Decodes an encoded word encoded with the 'Q' encoding (described in - * RFC 2047) found in a header field body. - * - * @param encodedWord the encoded word to decode. - * @param charset the Java charset to use. - * @return the decoded string. - * @throws UnsupportedEncodingException if the given Java charset isn't - * supported. - */ - public static String decodeQ(String encodedWord, String charset) - throws UnsupportedEncodingException { - - /* - * Replace _ with =20 - */ - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < encodedWord.length(); i++) { - char c = encodedWord.charAt(i); - if (c == '_') { - sb.append("=20"); - } else { - sb.append(c); - } - } - - return new String(decodeBaseQuotedPrintable(sb.toString()), charset); - } - - /** - * Decodes a string containing encoded words as defined by RFC 2047. - * Encoded words in have the form - * =?charset?enc?Encoded word?= where enc is either 'Q' or 'q' for - * quoted-printable and 'B' or 'b' for Base64. - * - * @param body the string to decode. - * @return the decoded string. - */ - public static String decodeEncodedWords(String body) { - StringBuffer sb = new StringBuffer(); - - int p1 = 0; - int p2 = 0; - - try { - - /* - * Encoded words in headers have the form - * =?charset?enc?Encoded word?= where enc is either 'Q' or 'q' for - * quoted printable and 'B' and 'b' for Base64 - */ - - while (p2 < body.length()) { - /* - * Find beginning of first encoded word - */ - p1 = body.indexOf("=?", p2); - if (p1 == -1) { - /* - * None found. Emit the rest of the header and exit. - */ - sb.append(body.substring(p2)); - break; - } - - /* - * p2 points to the previously found end marker or the start - * of the entire header text. Append the text between that - * marker and the one pointed to by p1. - */ - if (p1 - p2 > 0) { - sb.append(body.substring(p2, p1)); - } - - /* - * Find the first and second '?':s after the marker pointed to - * by p1. - */ - int t1 = body.indexOf('?', p1 + 2); - int t2 = t1 != -1 ? body.indexOf('?', t1 + 1) : -1; - - /* - * Find this words end marker. - */ - p2 = t2 != -1 ? body.indexOf("?=", t2 + 1) : -1; - if (p2 == -1) { - if (t2 != -1 && (body.length() - 1 == t2 || body.charAt(t2 + 1) == '=')) { - /* - * Treat "=?charset?enc?" and "=?charset?enc?=" as - * empty strings. - */ - p2 = t2; - } else { - /* - * No end marker was found. Append the rest of the - * header and exit. - */ - sb.append(body.substring(p1)); - break; - } - } - - /* - * [p1+2, t1] -> charset - * [t1+1, t2] -> encoding - * [t2+1, p2] -> encoded word - */ - - String decodedWord = null; - if (t2 == p2) { - /* - * The text is empty - */ - decodedWord = ""; - } else { - - String mimeCharset = body.substring(p1 + 2, t1); - String enc = body.substring(t1 + 1, t2); - String encodedWord = body.substring(t2 + 1, p2); - - /* - * Convert the MIME charset to a corresponding Java one. - */ - String charset = CharsetUtil.toJavaCharset(mimeCharset); - if (charset == null) { - decodedWord = body.substring(p1, p2 + 2); - if (log.isWarnEnabled()) { - log.warn("MIME charset '" + mimeCharset - + "' in header field doesn't have a " - +"corresponding Java charset"); - } - } else if (!CharsetUtil.isDecodingSupported(charset)) { - decodedWord = body.substring(p1, p2 + 2); - if (log.isWarnEnabled()) { - log.warn("Current JDK doesn't support decoding " - + "of charset '" + charset - + "' (MIME charset '" - + mimeCharset + "')"); - } - } else { - if (enc.equalsIgnoreCase("Q")) { - decodedWord = DecoderUtil.decodeQ(encodedWord, charset); - } else if (enc.equalsIgnoreCase("B")) { - decodedWord = DecoderUtil.decodeB(encodedWord, charset); - } else { - decodedWord = encodedWord; - if (log.isWarnEnabled()) { - log.warn("Warning: Unknown encoding in " - + "header field '" + enc + "'"); - } - } - } - } - p2 += 2; - sb.append(decodedWord); - } - } catch (Throwable t) { - log.error("Decoding header field body '" + body + "'", t); - } - - return sb.toString(); - } -} diff --git a/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java b/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java deleted file mode 100644 index eb3f09c9a..000000000 --- a/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java +++ /dev/null @@ -1,227 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Performs Quoted-Printable decoding on an underlying stream. - * - * - * - * @version $Id: QuotedPrintableInputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $ - */ -public class QuotedPrintableInputStream extends InputStream { - private static Log log = LogFactory.getLog(QuotedPrintableInputStream.class); - - private InputStream stream; - ByteQueue byteq = new ByteQueue(); - ByteQueue pushbackq = new ByteQueue(); - private byte state = 0; - - public QuotedPrintableInputStream(InputStream stream) { - this.stream = stream; - } - - /** - * Closes the underlying stream. - * - * @throws IOException on I/O errors. - */ - public void close() throws IOException { - stream.close(); - } - - public int read() throws IOException { - fillBuffer(); - if (byteq.count() == 0) - return -1; - else { - byte val = byteq.dequeue(); - if (val >= 0) - return val; - else - return val & 0xFF; - } - } - - /** - * Pulls bytes out of the underlying stream and places them in the - * pushback queue. This is necessary (vs. reading from the - * underlying stream directly) to detect and filter out "transport - * padding" whitespace, i.e., all whitespace that appears immediately - * before a CRLF. - * - * @throws IOException Underlying stream threw IOException. - */ - private void populatePushbackQueue() throws IOException { - //Debug.verify(pushbackq.count() == 0, "PopulatePushbackQueue called when pushback queue was not empty!"); - - if (pushbackq.count() != 0) - return; - - while (true) { - int i = stream.read(); - switch (i) { - case -1: - // stream is done - pushbackq.clear(); // discard any whitespace preceding EOF - return; - case ' ': - case '\t': - pushbackq.enqueue((byte)i); - break; - case '\r': - case '\n': - pushbackq.clear(); // discard any whitespace preceding EOL - pushbackq.enqueue((byte)i); - return; - default: - pushbackq.enqueue((byte)i); - return; - } - } - } - - /** - * Causes the pushback queue to get populated if it is empty, then - * consumes and decodes bytes out of it until one or more bytes are - * in the byte queue. This decoding step performs the actual QP - * decoding. - * - * @throws IOException Underlying stream threw IOException. - */ - private void fillBuffer() throws IOException { - byte msdChar = 0; // first digit of escaped num - while (byteq.count() == 0) { - if (pushbackq.count() == 0) { - populatePushbackQueue(); - if (pushbackq.count() == 0) - return; - } - - byte b = (byte)pushbackq.dequeue(); - - switch (state) { - case 0: // start state, no bytes pending - if (b != '=') { - byteq.enqueue(b); - break; // state remains 0 - } else { - state = 1; - break; - } - case 1: // encountered "=" so far - if (b == '\r') { - state = 2; - break; - } else if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) { - state = 3; - msdChar = b; // save until next digit encountered - break; - } else if (b == '=') { - /* - * Special case when == is encountered. - * Emit one = and stay in this state. - */ - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; got =="); - } - byteq.enqueue((byte)'='); - break; - } else { - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; expected \\r or " - + "[0-9A-Z], got " + b); - } - state = 0; - byteq.enqueue((byte)'='); - byteq.enqueue(b); - break; - } - case 2: // encountered "=\r" so far - if (b == '\n') { - state = 0; - break; - } else { - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; expected " - + (int)'\n' + ", got " + b); - } - state = 0; - byteq.enqueue((byte)'='); - byteq.enqueue((byte)'\r'); - byteq.enqueue(b); - break; - } - case 3: // encountered = so far; expecting another to complete the octet - if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) { - byte msd = asciiCharToNumericValue(msdChar); - byte low = asciiCharToNumericValue(b); - state = 0; - byteq.enqueue((byte)((msd << 4) | low)); - break; - } else { - if (log.isWarnEnabled()) { - log.warn("Malformed MIME; expected " - + "[0-9A-Z], got " + b); - } - state = 0; - byteq.enqueue((byte)'='); - byteq.enqueue(msdChar); - byteq.enqueue(b); - break; - } - default: // should never happen - log.error("Illegal state: " + state); - state = 0; - byteq.enqueue(b); - break; - } - } - } - - /** - * Converts '0' => 0, 'A' => 10, etc. - * @param c ASCII character value. - * @return Numeric value of hexadecimal character. - */ - private byte asciiCharToNumericValue(byte c) { - if (c >= '0' && c <= '9') { - return (byte)(c - '0'); - } else if (c >= 'A' && c <= 'Z') { - return (byte)(0xA + (c - 'A')); - } else if (c >= 'a' && c <= 'z') { - return (byte)(0xA + (c - 'a')); - } else { - /* - * This should never happen since all calls to this method - * are preceded by a check that c is in [0-9A-Za-z] - */ - throw new IllegalArgumentException((char) c - + " is not a hexadecimal digit"); - } - } - -} diff --git a/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java b/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java deleted file mode 100644 index dc32caf36..000000000 --- a/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java +++ /dev/null @@ -1,272 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.decoder; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * UnboundedFifoByteBuffer is a very efficient buffer implementation. - * According to performance testing, it exhibits a constant access time, but it - * also outperforms ArrayList when used for the same purpose. - *

- * The removal order of an UnboundedFifoByteBuffer is based on the insertion - * order; elements are removed in the same order in which they were added. - * The iteration order is the same as the removal order. - *

- * The {@link #remove()} and {@link #get()} operations perform in constant time. - * The {@link #add(Object)} operation performs in amortized constant time. All - * other operations perform in linear time or worse. - *

- * Note that this implementation is not synchronized. The following can be - * used to provide synchronized access to your UnboundedFifoByteBuffer: - *

- *   Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoByteBuffer());
- * 
- *

- * This buffer prevents null objects from being added. - * - * @since Commons Collections 3.0 (previously in main package v2.1) - * @version $Revision: 1.1 $ $Date: 2004/08/24 06:52:02 $ - * - * - * - * - * - * - */ -class UnboundedFifoByteBuffer { - - protected byte[] buffer; - protected int head; - protected int tail; - - /** - * Constructs an UnboundedFifoByteBuffer with the default number of elements. - * It is exactly the same as performing the following: - * - *

-     *   new UnboundedFifoByteBuffer(32);
-     * 
- */ - public UnboundedFifoByteBuffer() { - this(32); - } - - /** - * Constructs an UnboundedFifoByteBuffer with the specified number of elements. - * The integer must be a positive integer. - * - * @param initialSize the initial size of the buffer - * @throws IllegalArgumentException if the size is less than 1 - */ - public UnboundedFifoByteBuffer(int initialSize) { - if (initialSize <= 0) { - throw new IllegalArgumentException("The size must be greater than 0"); - } - buffer = new byte[initialSize + 1]; - head = 0; - tail = 0; - } - - /** - * Returns the number of elements stored in the buffer. - * - * @return this buffer's size - */ - public int size() { - int size = 0; - - if (tail < head) { - size = buffer.length - head + tail; - } else { - size = tail - head; - } - - return size; - } - - /** - * Returns true if this buffer is empty; false otherwise. - * - * @return true if this buffer is empty - */ - public boolean isEmpty() { - return (size() == 0); - } - - /** - * Adds the given element to this buffer. - * - * @param b the byte to add - * @return true, always - */ - public boolean add(final byte b) { - - if (size() + 1 >= buffer.length) { - byte[] tmp = new byte[((buffer.length - 1) * 2) + 1]; - - int j = 0; - for (int i = head; i != tail;) { - tmp[j] = buffer[i]; - buffer[i] = 0; - - j++; - i++; - if (i == buffer.length) { - i = 0; - } - } - - buffer = tmp; - head = 0; - tail = j; - } - - buffer[tail] = b; - tail++; - if (tail >= buffer.length) { - tail = 0; - } - return true; - } - - /** - * Returns the next object in the buffer. - * - * @return the next object in the buffer - * @throws BufferUnderflowException if this buffer is empty - */ - public byte get() { - if (isEmpty()) { - throw new IllegalStateException("The buffer is already empty"); - } - - return buffer[head]; - } - - /** - * Removes the next object from the buffer - * - * @return the removed object - * @throws BufferUnderflowException if this buffer is empty - */ - public byte remove() { - if (isEmpty()) { - throw new IllegalStateException("The buffer is already empty"); - } - - byte element = buffer[head]; - - head++; - if (head >= buffer.length) { - head = 0; - } - - return element; - } - - /** - * Increments the internal index. - * - * @param index the index to increment - * @return the updated index - */ - private int increment(int index) { - index++; - if (index >= buffer.length) { - index = 0; - } - return index; - } - - /** - * Decrements the internal index. - * - * @param index the index to decrement - * @return the updated index - */ - private int decrement(int index) { - index--; - if (index < 0) { - index = buffer.length - 1; - } - return index; - } - - /** - * Returns an iterator over this buffer's elements. - * - * @return an iterator over this buffer's elements - */ - public Iterator iterator() { - return new Iterator() { - - private int index = head; - private int lastReturnedIndex = -1; - - public boolean hasNext() { - return index != tail; - - } - - public Object next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - lastReturnedIndex = index; - index = increment(index); - return new Byte(buffer[lastReturnedIndex]); - } - - public void remove() { - if (lastReturnedIndex == -1) { - throw new IllegalStateException(); - } - - // First element can be removed quickly - if (lastReturnedIndex == head) { - UnboundedFifoByteBuffer.this.remove(); - lastReturnedIndex = -1; - return; - } - - // Other elements require us to shift the subsequent elements - int i = lastReturnedIndex + 1; - while (i != tail) { - if (i >= buffer.length) { - buffer[i - 1] = buffer[0]; - i = 0; - } else { - buffer[i - 1] = buffer[i]; - i++; - } - } - - lastReturnedIndex = -1; - tail = decrement(tail); - buffer[tail] = 0; - index = decrement(index); - } - - }; - } - -} \ No newline at end of file diff --git a/src/org/apache/james/mime4j/field/AddressListField.java b/src/org/apache/james/mime4j/field/AddressListField.java deleted file mode 100644 index 0e4297c76..000000000 --- a/src/org/apache/james/mime4j/field/AddressListField.java +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.field.address.AddressList; -import org.apache.james.mime4j.field.address.parser.ParseException; - -public class AddressListField extends Field { - private AddressList addressList; - private ParseException parseException; - - protected AddressListField(String name, String body, String raw, AddressList addressList, ParseException parseException) { - super(name, body, raw); - this.addressList = addressList; - this.parseException = parseException; - } - - public AddressList getAddressList() { - return addressList; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - AddressList addressList = null; - ParseException parseException = null; - try { - addressList = AddressList.parse(body); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new AddressListField(name, body, raw, addressList, parseException); - } - } -} diff --git a/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java b/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java deleted file mode 100644 index eb6151377..000000000 --- a/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - - - -/** - * Represents a Content-Transfer-Encoding field. - * - * - * @version $Id: ContentTransferEncodingField.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -public class ContentTransferEncodingField extends Field { - /** - * The 7bit encoding. - */ - public static final String ENC_7BIT = "7bit"; - /** - * The 8bit encoding. - */ - public static final String ENC_8BIT = "8bit"; - /** - * The binary encoding. - */ - public static final String ENC_BINARY = "binary"; - /** - * The quoted-printable encoding. - */ - public static final String ENC_QUOTED_PRINTABLE = "quoted-printable"; - /** - * The base64 encoding. - */ - public static final String ENC_BASE64 = "base64"; - - private String encoding; - - protected ContentTransferEncodingField(String name, String body, String raw, String encoding) { - super(name, body, raw); - this.encoding = encoding; - } - - /** - * Gets the encoding defined in this field. - * - * @return the encoding or an empty string if not set. - */ - public String getEncoding() { - return encoding; - } - - /** - * Gets the encoding of the given field if. Returns the default - * 7bit if not set or if - * f is null. - * - * @return the encoding. - */ - public static String getEncoding(ContentTransferEncodingField f) { - if (f != null && f.getEncoding().length() != 0) { - return f.getEncoding(); - } - return ENC_7BIT; - } - - public static class Parser implements FieldParser { - public Field parse(final String name, final String body, final String raw) { - final String encoding = body.trim().toLowerCase(); - return new ContentTransferEncodingField(name, body, raw, encoding); - } - } -} diff --git a/src/org/apache/james/mime4j/field/ContentTypeField.java b/src/org/apache/james/mime4j/field/ContentTypeField.java deleted file mode 100644 index 51616419d..000000000 --- a/src/org/apache/james/mime4j/field/ContentTypeField.java +++ /dev/null @@ -1,256 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.field.contenttype.parser.ContentTypeParser; -import org.apache.james.mime4j.field.contenttype.parser.ParseException; -import org.apache.james.mime4j.field.contenttype.parser.TokenMgrError; - -/** - * Represents a Content-Type field. - * - *

TODO: Remove dependency on Java 1.4 regexps

- * - * - * @version $Id: ContentTypeField.java,v 1.6 2005/01/27 14:16:31 ntherning Exp $ - */ -public class ContentTypeField extends Field { - - /** - * The prefix of all multipart MIME types. - */ - public static final String TYPE_MULTIPART_PREFIX = "multipart/"; - /** - * The multipart/digest MIME type. - */ - public static final String TYPE_MULTIPART_DIGEST = "multipart/digest"; - /** - * The text/plain MIME type. - */ - public static final String TYPE_TEXT_PLAIN = "text/plain"; - /** - * The message/rfc822 MIME type. - */ - public static final String TYPE_MESSAGE_RFC822 = "message/rfc822"; - /** - * The name of the boundary parameter. - */ - public static final String PARAM_BOUNDARY = "boundary"; - /** - * The name of the charset parameter. - */ - public static final String PARAM_CHARSET = "charset"; - - private String mimeType = ""; - private Map parameters = null; - private ParseException parseException; - - protected ContentTypeField(String name, String body, String raw, String mimeType, Map parameters, ParseException parseException) { - super(name, body, raw); - this.mimeType = mimeType; - this.parameters = parameters; - this.parseException = parseException; - } - - /** - * Gets the exception that was raised during parsing of - * the field value, if any; otherwise, null. - */ - public ParseException getParseException() { - return parseException; - } - - /** - * Gets the MIME type defined in this Content-Type field. - * - * @return the MIME type or an empty string if not set. - */ - public String getMimeType() { - return mimeType; - } - - /** - * Gets the MIME type defined in the child's - * Content-Type field or derives a MIME type from the parent - * if child is null or hasn't got a MIME type value set. - * If child's MIME type is multipart but no boundary - * has been set the MIME type of child will be derived from - * the parent. - * - * @param child the child. - * @param parent the parent. - * @return the MIME type. - */ - public static String getMimeType(ContentTypeField child, - ContentTypeField parent) { - - if (child == null || child.getMimeType().length() == 0 - || child.isMultipart() && child.getBoundary() == null) { - - if (parent != null && parent.isMimeType(TYPE_MULTIPART_DIGEST)) { - return TYPE_MESSAGE_RFC822; - } else { - return TYPE_TEXT_PLAIN; - } - } - - return child.getMimeType(); - } - - /** - * Gets the value of a parameter. Parameter names are case-insensitive. - * - * @param name the name of the parameter to get. - * @return the parameter value or null if not set. - */ - public String getParameter(String name) { - return parameters != null - ? (String) parameters.get(name.toLowerCase()) - : null; - } - - /** - * Gets all parameters. - * - * @return the parameters. - */ - public Map getParameters() { - return parameters != null - ? Collections.unmodifiableMap(parameters) - : Collections.EMPTY_MAP; - } - - /** - * Gets the value of the boundary parameter if set. - * - * @return the boundary parameter value or null - * if not set. - */ - public String getBoundary() { - return getParameter(PARAM_BOUNDARY); - } - - /** - * Gets the value of the charset parameter if set. - * - * @return the charset parameter value or null - * if not set. - */ - public String getCharset() { - return getParameter(PARAM_CHARSET); - } - - /** - * Gets the value of the charset parameter if set for the - * given field. Returns the default us-ascii if not set or if - * f is null. - * - * @return the charset parameter value. - */ - public static String getCharset(ContentTypeField f) { - if (f != null) { - if (f.getCharset() != null && f.getCharset().length() > 0) { - return f.getCharset(); - } - } - return "us-ascii"; - } - - /** - * Determines if the MIME type of this field matches the given one. - * - * @param mimeType the MIME type to match against. - * @return true if the MIME type of this field matches, - * false otherwise. - */ - public boolean isMimeType(String mimeType) { - return this.mimeType.equalsIgnoreCase(mimeType); - } - - /** - * Determines if the MIME type of this field is multipart/*. - * - * @return true if this field is has a multipart/* - * MIME type, false otherwise. - */ - public boolean isMultipart() { - return mimeType.startsWith(TYPE_MULTIPART_PREFIX); - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - ParseException parseException = null; - String mimeType = ""; - Map parameters = null; - - ContentTypeParser parser = new ContentTypeParser(new StringReader(body)); - try { - parser.parseAll(); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - catch (TokenMgrError e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = new ParseException(e.getMessage()); - } - - try { - final String type = parser.getType(); - final String subType = parser.getSubType(); - - if (type != null && subType != null) { - mimeType = (type + "/" + parser.getSubType()).toLowerCase(); - - ArrayList paramNames = parser.getParamNames(); - ArrayList paramValues = parser.getParamValues(); - - if (paramNames != null && paramValues != null) { - for (int i = 0; i < paramNames.size() && i < paramValues.size(); i++) { - if (parameters == null) - parameters = new HashMap((int)(paramNames.size() * 1.3 + 1)); - String paramName = ((String)paramNames.get(i)).toLowerCase(); - String paramValue = ((String)paramValues.get(i)); - parameters.put(paramName, paramValue); - } - } - } - } - catch (NullPointerException npe) { - } - return new ContentTypeField(name, body, raw, mimeType, parameters, parseException); - } - } -} diff --git a/src/org/apache/james/mime4j/field/DateTimeField.java b/src/org/apache/james/mime4j/field/DateTimeField.java deleted file mode 100644 index a7b24b5bd..000000000 --- a/src/org/apache/james/mime4j/field/DateTimeField.java +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.field.datetime.DateTime; -import org.apache.james.mime4j.field.datetime.parser.ParseException; - -import java.util.Date; - -public class DateTimeField extends Field { - private Date date; - private ParseException parseException; - - protected DateTimeField(String name, String body, String raw, Date date, ParseException parseException) { - super(name, body, raw); - this.date = date; - this.parseException = parseException; - } - - public Date getDate() { - return date; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - Date date = null; - ParseException parseException = null; - try { - date = DateTime.parse(body).getDate(); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new DateTimeField(name, body, raw, date, parseException); - } - } -} diff --git a/src/org/apache/james/mime4j/field/DefaultFieldParser.java b/src/org/apache/james/mime4j/field/DefaultFieldParser.java deleted file mode 100644 index 84fcdcb2d..000000000 --- a/src/org/apache/james/mime4j/field/DefaultFieldParser.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2006 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field; - -public class DefaultFieldParser extends DelegatingFieldParser { - - public DefaultFieldParser() { - setFieldParser(Field.CONTENT_TRANSFER_ENCODING, new ContentTransferEncodingField.Parser()); - setFieldParser(Field.CONTENT_TYPE, new ContentTypeField.Parser()); - - final DateTimeField.Parser dateTimeParser = new DateTimeField.Parser(); - setFieldParser(Field.DATE, dateTimeParser); - setFieldParser(Field.RESENT_DATE, dateTimeParser); - - final MailboxListField.Parser mailboxListParser = new MailboxListField.Parser(); - setFieldParser(Field.FROM, mailboxListParser); - setFieldParser(Field.RESENT_FROM, mailboxListParser); - - final MailboxField.Parser mailboxParser = new MailboxField.Parser(); - setFieldParser(Field.SENDER, mailboxParser); - setFieldParser(Field.RESENT_SENDER, mailboxParser); - - final AddressListField.Parser addressListParser = new AddressListField.Parser(); - setFieldParser(Field.TO, addressListParser); - setFieldParser(Field.RESENT_TO, addressListParser); - setFieldParser(Field.CC, addressListParser); - setFieldParser(Field.RESENT_CC, addressListParser); - setFieldParser(Field.BCC, addressListParser); - setFieldParser(Field.RESENT_BCC, addressListParser); - setFieldParser(Field.REPLY_TO, addressListParser); - } -} diff --git a/src/org/apache/james/mime4j/field/DelegatingFieldParser.java b/src/org/apache/james/mime4j/field/DelegatingFieldParser.java deleted file mode 100644 index e7787a336..000000000 --- a/src/org/apache/james/mime4j/field/DelegatingFieldParser.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2006 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field; - -import java.util.HashMap; -import java.util.Map; - -public class DelegatingFieldParser implements FieldParser { - - private Map parsers = new HashMap(); - private FieldParser defaultParser = new UnstructuredField.Parser(); - - /** - * Sets the parser used for the field named name. - * @param name the name of the field - * @param parser the parser for fields named name - */ - public void setFieldParser(final String name, final FieldParser parser) { - parsers.put(name.toLowerCase(), parser); - } - - public FieldParser getParser(final String name) { - final FieldParser field = (FieldParser) parsers.get(name.toLowerCase()); - if(field==null) { - return defaultParser; - } - return field; - } - - public Field parse(final String name, final String body, final String raw) { - final FieldParser parser = getParser(name); - return parser.parse(name, body, raw); - } -} diff --git a/src/org/apache/james/mime4j/field/Field.java b/src/org/apache/james/mime4j/field/Field.java deleted file mode 100644 index 7c2a20dc8..000000000 --- a/src/org/apache/james/mime4j/field/Field.java +++ /dev/null @@ -1,192 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The base class of all field classes. - * - * - * @version $Id: Field.java,v 1.6 2004/10/25 07:26:46 ntherning Exp $ - */ -public abstract class Field { - public static final String SENDER = "Sender"; - public static final String FROM = "From"; - public static final String TO = "To"; - public static final String CC = "Cc"; - public static final String BCC = "Bcc"; - public static final String REPLY_TO = "Reply-To"; - public static final String RESENT_SENDER = "Resent-Sender"; - public static final String RESENT_FROM = "Resent-From"; - public static final String RESENT_TO = "Resent-To"; - public static final String RESENT_CC = "Resent-Cc"; - public static final String RESENT_BCC = "Resent-Bcc"; - - public static final String DATE = "Date"; - public static final String RESENT_DATE = "Resent-Date"; - - public static final String SUBJECT = "Subject"; - public static final String CONTENT_TYPE = "Content-Type"; - public static final String CONTENT_TRANSFER_ENCODING = - "Content-Transfer-Encoding"; - - private static final String FIELD_NAME_PATTERN = - "^([\\x21-\\x39\\x3b-\\x7e]+)[ \t]*:"; - private static final Pattern fieldNamePattern = - Pattern.compile(FIELD_NAME_PATTERN); - - private static final DefaultFieldParser parser = new DefaultFieldParser(); - - private final String name; - private final String body; - private final String raw; - - protected Field(final String name, final String body, final String raw) { - this.name = name; - this.body = body; - this.raw = raw; - } - - /** - * Parses the given string and returns an instance of the - * Field class. The type of the class returned depends on - * the field name: - * - * - * - * - * - * - *
Field nameClass returnedContent-Typeorg.apache.james.mime4j.field.ContentTypeFieldotherorg.apache.james.mime4j.field.UnstructuredField
- * - * @param s the string to parse. - * @return a Field instance. - * @throws IllegalArgumentException on parse errors. - */ - public static Field parse(final String raw) { - - /* - * Unfold the field. - */ - final String unfolded = raw.replaceAll("\r|\n", ""); - - /* - * Split into name and value. - */ - final Matcher fieldMatcher = fieldNamePattern.matcher(unfolded); - if (!fieldMatcher.find()) { - throw new IllegalArgumentException("Invalid field in string"); - } - final String name = fieldMatcher.group(1); - - String body = unfolded.substring(fieldMatcher.end()); - if (body.length() > 0 && body.charAt(0) == ' ') { - body = body.substring(1); - } - - return parser.parse(name, body, raw); - } - - /** - * Gets the default parser used to parse fields. - * @return the default field parser - */ - public static DefaultFieldParser getParser() { - return parser; - } - - /** - * Gets the name of the field (Subject, - * From, etc). - * - * @return the field name. - */ - public String getName() { - return name; - } - - /** - * Gets the original raw field string. - * - * @return the original raw field string. - */ - public String getRaw() { - return raw; - } - - /** - * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field - * body string. - * - * @return the unfolded unparsed field body string. - */ - public String getBody() { - return body; - } - - /** - * Determines if this is a Content-Type field. - * - * @return true if this is a Content-Type field, - * false otherwise. - */ - public boolean isContentType() { - return CONTENT_TYPE.equalsIgnoreCase(name); - } - - /** - * Determines if this is a Subject field. - * - * @return true if this is a Subject field, - * false otherwise. - */ - public boolean isSubject() { - return SUBJECT.equalsIgnoreCase(name); - } - - /** - * Determines if this is a From field. - * - * @return true if this is a From field, - * false otherwise. - */ - public boolean isFrom() { - return FROM.equalsIgnoreCase(name); - } - - /** - * Determines if this is a To field. - * - * @return true if this is a To field, - * false otherwise. - */ - public boolean isTo() { - return TO.equalsIgnoreCase(name); - } - - /** - * @see #getRaw() - */ - public String toString() { - return raw; - } -} diff --git a/src/org/apache/james/mime4j/field/FieldParser.java b/src/org/apache/james/mime4j/field/FieldParser.java deleted file mode 100644 index 4f33c9e26..000000000 --- a/src/org/apache/james/mime4j/field/FieldParser.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2006 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field; - -public interface FieldParser { - - Field parse(final String name, final String body, final String raw); -} diff --git a/src/org/apache/james/mime4j/field/MailboxField.java b/src/org/apache/james/mime4j/field/MailboxField.java deleted file mode 100644 index 96cca551f..000000000 --- a/src/org/apache/james/mime4j/field/MailboxField.java +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.field.address.AddressList; -import org.apache.james.mime4j.field.address.Mailbox; -import org.apache.james.mime4j.field.address.MailboxList; -import org.apache.james.mime4j.field.address.parser.ParseException; - -public class MailboxField extends Field { - private final Mailbox mailbox; - private final ParseException parseException; - - protected MailboxField(final String name, final String body, final String raw, final Mailbox mailbox, final ParseException parseException) { - super(name, body, raw); - this.mailbox = mailbox; - this.parseException = parseException; - } - - public Mailbox getMailbox() { - return mailbox; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - Mailbox mailbox = null; - ParseException parseException = null; - try { - MailboxList mailboxList = AddressList.parse(body).flatten(); - if (mailboxList.size() > 0) { - mailbox = mailboxList.get(0); - } - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new MailboxField(name, body, raw, mailbox, parseException); - } - } -} diff --git a/src/org/apache/james/mime4j/field/MailboxListField.java b/src/org/apache/james/mime4j/field/MailboxListField.java deleted file mode 100644 index efb18cd35..000000000 --- a/src/org/apache/james/mime4j/field/MailboxListField.java +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.field.address.AddressList; -import org.apache.james.mime4j.field.address.MailboxList; -import org.apache.james.mime4j.field.address.parser.ParseException; - -public class MailboxListField extends Field { - - private MailboxList mailboxList; - private ParseException parseException; - - protected MailboxListField(final String name, final String body, final String raw, final MailboxList mailboxList, final ParseException parseException) { - super(name, body, raw); - this.mailboxList = mailboxList; - this.parseException = parseException; - } - - public MailboxList getMailboxList() { - return mailboxList; - } - - public ParseException getParseException() { - return parseException; - } - - public static class Parser implements FieldParser { - private static Log log = LogFactory.getLog(Parser.class); - - public Field parse(final String name, final String body, final String raw) { - MailboxList mailboxList = null; - ParseException parseException = null; - try { - mailboxList = AddressList.parse(body).flatten(); - } - catch (ParseException e) { - if (log.isDebugEnabled()) { - log.debug("Parsing value '" + body + "': "+ e.getMessage()); - } - parseException = e; - } - return new MailboxListField(name, body, raw, mailboxList, parseException); - } - } -} diff --git a/src/org/apache/james/mime4j/field/UnstructuredField.java b/src/org/apache/james/mime4j/field/UnstructuredField.java deleted file mode 100644 index 5e2adf9f2..000000000 --- a/src/org/apache/james/mime4j/field/UnstructuredField.java +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field; - -import org.apache.james.mime4j.decoder.DecoderUtil; - - -/** - * Simple unstructured field such as Subject. - * - * - * @version $Id: UnstructuredField.java,v 1.3 2004/10/25 07:26:46 ntherning Exp $ - */ -public class UnstructuredField extends Field { - private String value; - - protected UnstructuredField(String name, String body, String raw, String value) { - super(name, body, raw); - this.value = value; - } - - public String getValue() { - return value; - } - - public static class Parser implements FieldParser { - public Field parse(final String name, final String body, final String raw) { - final String value = DecoderUtil.decodeEncodedWords(body); - return new UnstructuredField(name, body, raw, value); - } - } -} diff --git a/src/org/apache/james/mime4j/field/address/Address.java b/src/org/apache/james/mime4j/field/address/Address.java deleted file mode 100644 index 47cee0ba0..000000000 --- a/src/org/apache/james/mime4j/field/address/Address.java +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * The abstract base for classes that represent RFC2822 addresses. - * This includes groups and mailboxes. - * - * Currently, no public methods are introduced on this class. - * - * - */ -public abstract class Address { - - /** - * Adds any mailboxes represented by this address - * into the given ArrayList. Note that this method - * has default (package) access, so a doAddMailboxesTo - * method is needed to allow the behavior to be - * overridden by subclasses. - */ - final void addMailboxesTo(ArrayList results) { - doAddMailboxesTo(results); - } - - /** - * Adds any mailboxes represented by this address - * into the given ArrayList. Must be overridden by - * concrete subclasses. - */ - protected abstract void doAddMailboxesTo(ArrayList results); - -} diff --git a/src/org/apache/james/mime4j/field/address/AddressList.java b/src/org/apache/james/mime4j/field/address/AddressList.java deleted file mode 100644 index 75072bde4..000000000 --- a/src/org/apache/james/mime4j/field/address/AddressList.java +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import org.apache.james.mime4j.field.address.parser.AddressListParser; -import org.apache.james.mime4j.field.address.parser.ParseException; - -import java.io.StringReader; -import java.util.ArrayList; - -/** - * An immutable, random-access list of Address objects. - * - * - */ -public class AddressList { - - private ArrayList addresses; - - /** - * @param addresses An ArrayList that contains only Address objects. - * @param dontCopy true iff it is not possible for the addresses ArrayList to be modified by someone else. - */ - public AddressList(ArrayList addresses, boolean dontCopy) { - if (addresses != null) - this.addresses = (dontCopy ? addresses : (ArrayList) addresses.clone()); - else - this.addresses = new ArrayList(0); - } - - /** - * The number of elements in this list. - */ - public int size() { - return addresses.size(); - } - - /** - * Gets an address. - */ - public Address get(int index) { - if (0 > index || size() <= index) - throw new IndexOutOfBoundsException(); - return (Address) addresses.get(index); - } - - /** - * Returns a flat list of all mailboxes represented - * in this address list. Use this if you don't care - * about grouping. - */ - public MailboxList flatten() { - // in the common case, all addresses are mailboxes - boolean groupDetected = false; - for (int i = 0; i < size(); i++) { - if (!(get(i) instanceof Mailbox)) { - groupDetected = true; - break; - } - } - - if (!groupDetected) - return new MailboxList(addresses, true); - - ArrayList results = new ArrayList(); - for (int i = 0; i < size(); i++) { - Address addr = get(i); - addr.addMailboxesTo(results); - } - - // copy-on-construct this time, because subclasses - // could have held onto a reference to the results - return new MailboxList(results, false); - } - - /** - * Dumps a representation of this address list to - * stdout, for debugging purposes. - */ - public void print() { - for (int i = 0; i < size(); i++) { - Address addr = get(i); - System.out.println(addr.toString()); - } - } - - - - /** - * Parse the address list string, such as the value - * of a From, To, Cc, Bcc, Sender, or Reply-To - * header. - * - * The string MUST be unfolded already. - */ - public static AddressList parse(String rawAddressList) throws ParseException { - AddressListParser parser = new AddressListParser(new StringReader(rawAddressList)); - return Builder.getInstance().buildAddressList(parser.parse()); - } - - /** - * Test console. - */ - public static void main(String[] args) throws Exception { - java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)); - while (true) { - try { - System.out.print("> "); - String line = reader.readLine(); - if (line.length() == 0 || line.toLowerCase().equals("exit") || line.toLowerCase().equals("quit")) { - System.out.println("Goodbye."); - return; - } - AddressList list = parse(line); - list.print(); - } - catch(Exception e) { - e.printStackTrace(); - Thread.sleep(300); - } - } - } -} diff --git a/src/org/apache/james/mime4j/field/address/Builder.java b/src/org/apache/james/mime4j/field/address/Builder.java deleted file mode 100644 index 3699afed7..000000000 --- a/src/org/apache/james/mime4j/field/address/Builder.java +++ /dev/null @@ -1,244 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; -import java.util.Iterator; - -import org.apache.james.mime4j.decoder.DecoderUtil; -import org.apache.james.mime4j.field.address.parser.*; -import org.apache.james.mime4j.field.address.parser.ASTaddr_spec; -import org.apache.james.mime4j.field.address.parser.ASTaddress; -import org.apache.james.mime4j.field.address.parser.ASTaddress_list; -import org.apache.james.mime4j.field.address.parser.ASTangle_addr; -import org.apache.james.mime4j.field.address.parser.ASTdomain; -import org.apache.james.mime4j.field.address.parser.ASTgroup_body; -import org.apache.james.mime4j.field.address.parser.ASTlocal_part; -import org.apache.james.mime4j.field.address.parser.ASTmailbox; -import org.apache.james.mime4j.field.address.parser.ASTname_addr; -import org.apache.james.mime4j.field.address.parser.ASTphrase; -import org.apache.james.mime4j.field.address.parser.ASTroute; -import org.apache.james.mime4j.field.address.parser.Node; -import org.apache.james.mime4j.field.address.parser.SimpleNode; -import org.apache.james.mime4j.field.address.parser.Token; - -/** - * Transforms the JJTree-generated abstract syntax tree - * into a graph of org.apache.james.mime4j.field.address objects. - * - * - */ -class Builder { - - private static Builder singleton = new Builder(); - - public static Builder getInstance() { - return singleton; - } - - - - public AddressList buildAddressList(ASTaddress_list node) { - ArrayList list = new ArrayList(); - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - ASTaddress childNode = (ASTaddress) node.jjtGetChild(i); - Address address = buildAddress(childNode); - list.add(address); - } - return new AddressList(list, true); - } - - private Address buildAddress(ASTaddress node) { - ChildNodeIterator it = new ChildNodeIterator(node); - Node n = it.nextNode(); - if (n instanceof ASTaddr_spec) { - return buildAddrSpec((ASTaddr_spec)n); - } - else if (n instanceof ASTangle_addr) { - return buildAngleAddr((ASTangle_addr)n); - } - else if (n instanceof ASTphrase) { - String name = buildString((ASTphrase)n, false); - Node n2 = it.nextNode(); - if (n2 instanceof ASTgroup_body) { - return new Group(name, buildGroupBody((ASTgroup_body)n2)); - } - else if (n2 instanceof ASTangle_addr) { - name = DecoderUtil.decodeEncodedWords(name); - return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2)); - } - else { - throw new IllegalStateException(); - } - } - else { - throw new IllegalStateException(); - } - } - - - - private MailboxList buildGroupBody(ASTgroup_body node) { - ArrayList results = new ArrayList(); - ChildNodeIterator it = new ChildNodeIterator(node); - while (it.hasNext()) { - Node n = it.nextNode(); - if (n instanceof ASTmailbox) - results.add(buildMailbox((ASTmailbox)n)); - else - throw new IllegalStateException(); - } - return new MailboxList(results, true); - } - - private Mailbox buildMailbox(ASTmailbox node) { - ChildNodeIterator it = new ChildNodeIterator(node); - Node n = it.nextNode(); - if (n instanceof ASTaddr_spec) { - return buildAddrSpec((ASTaddr_spec)n); - } - else if (n instanceof ASTangle_addr) { - return buildAngleAddr((ASTangle_addr)n); - } - else if (n instanceof ASTname_addr) { - return buildNameAddr((ASTname_addr)n); - } - else { - throw new IllegalStateException(); - } - } - - private NamedMailbox buildNameAddr(ASTname_addr node) { - ChildNodeIterator it = new ChildNodeIterator(node); - Node n = it.nextNode(); - String name; - if (n instanceof ASTphrase) { - name = buildString((ASTphrase)n, false); - } - else { - throw new IllegalStateException(); - } - - n = it.nextNode(); - if (n instanceof ASTangle_addr) { - name = DecoderUtil.decodeEncodedWords(name); - return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n)); - } - else { - throw new IllegalStateException(); - } - } - - private Mailbox buildAngleAddr(ASTangle_addr node) { - ChildNodeIterator it = new ChildNodeIterator(node); - DomainList route = null; - Node n = it.nextNode(); - if (n instanceof ASTroute) { - route = buildRoute((ASTroute)n); - n = it.nextNode(); - } - else if (n instanceof ASTaddr_spec) - ; // do nothing - else - throw new IllegalStateException(); - - if (n instanceof ASTaddr_spec) - return buildAddrSpec(route, (ASTaddr_spec)n); - else - throw new IllegalStateException(); - } - - private DomainList buildRoute(ASTroute node) { - ArrayList results = new ArrayList(node.jjtGetNumChildren()); - ChildNodeIterator it = new ChildNodeIterator(node); - while (it.hasNext()) { - Node n = it.nextNode(); - if (n instanceof ASTdomain) - results.add(buildString((ASTdomain)n, true)); - else - throw new IllegalStateException(); - } - return new DomainList(results, true); - } - - private Mailbox buildAddrSpec(ASTaddr_spec node) { - return buildAddrSpec(null, node); - } - private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) { - ChildNodeIterator it = new ChildNodeIterator(node); - String localPart = buildString((ASTlocal_part)it.nextNode(), true); - String domain = buildString((ASTdomain)it.nextNode(), true); - return new Mailbox(route, localPart, domain); - } - - - private String buildString(SimpleNode node, boolean stripSpaces) { - Token head = node.firstToken; - Token tail = node.lastToken; - StringBuffer out = new StringBuffer(); - - while (head != tail) { - out.append(head.image); - head = head.next; - if (!stripSpaces) - addSpecials(out, head.specialToken); - } - out.append(tail.image); - - return out.toString(); - } - - private void addSpecials(StringBuffer out, Token specialToken) { - if (specialToken != null) { - addSpecials(out, specialToken.specialToken); - out.append(specialToken.image); - } - } - - private static class ChildNodeIterator implements Iterator { - - private SimpleNode simpleNode; - private int index; - private int len; - - public ChildNodeIterator(SimpleNode simpleNode) { - this.simpleNode = simpleNode; - this.len = simpleNode.jjtGetNumChildren(); - this.index = 0; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return index < len; - } - - public Object next() { - return nextNode(); - } - - public Node nextNode() { - return simpleNode.jjtGetChild(index++); - } - - } -} diff --git a/src/org/apache/james/mime4j/field/address/DomainList.java b/src/org/apache/james/mime4j/field/address/DomainList.java deleted file mode 100644 index 23c377e9e..000000000 --- a/src/org/apache/james/mime4j/field/address/DomainList.java +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * An immutable, random-access list of Strings (that - * are supposedly domain names or domain literals). - * - * - */ -public class DomainList { - private ArrayList domains; - - /** - * @param domains An ArrayList that contains only String objects. - * @param dontCopy true iff it is not possible for the domains ArrayList to be modified by someone else. - */ - public DomainList(ArrayList domains, boolean dontCopy) { - if (domains != null) - this.domains = (dontCopy ? domains : (ArrayList) domains.clone()); - else - this.domains = new ArrayList(0); - } - - /** - * The number of elements in this list. - */ - public int size() { - return domains.size(); - } - - /** - * Gets the domain name or domain literal at the - * specified index. - * @throws IndexOutOfBoundsException If index is < 0 or >= size(). - */ - public String get(int index) { - if (0 > index || size() <= index) - throw new IndexOutOfBoundsException(); - return (String) domains.get(index); - } - - /** - * Returns the list of domains formatted as a route - * string (not including the trailing ':'). - */ - public String toRouteString() { - StringBuffer out = new StringBuffer(); - for (int i = 0; i < domains.size(); i++) { - out.append("@"); - out.append(get(i)); - if (i + 1 < domains.size()) - out.append(","); - } - return out.toString(); - } -} diff --git a/src/org/apache/james/mime4j/field/address/Group.java b/src/org/apache/james/mime4j/field/address/Group.java deleted file mode 100644 index eb4002708..000000000 --- a/src/org/apache/james/mime4j/field/address/Group.java +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * A named group of zero or more mailboxes. - * - * - */ -public class Group extends Address { - private String name; - private MailboxList mailboxList; - - /** - * @param name The group name. - * @param mailboxes The mailboxes in this group. - */ - public Group(String name, MailboxList mailboxes) { - this.name = name; - this.mailboxList = mailboxes; - } - - /** - * Returns the group name. - */ - public String getName() { - return name; - } - - /** - * Returns the mailboxes in this group. - */ - public MailboxList getMailboxes() { - return mailboxList; - } - - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append(name); - buf.append(":"); - for (int i = 0; i < mailboxList.size(); i++) { - buf.append(mailboxList.get(i).toString()); - if (i + 1 < mailboxList.size()) - buf.append(","); - } - buf.append(";"); - return buf.toString(); - } - - protected void doAddMailboxesTo(ArrayList results) { - for (int i = 0; i < mailboxList.size(); i++) - results.add(mailboxList.get(i)); - } -} diff --git a/src/org/apache/james/mime4j/field/address/Mailbox.java b/src/org/apache/james/mime4j/field/address/Mailbox.java deleted file mode 100644 index 57668abfe..000000000 --- a/src/org/apache/james/mime4j/field/address/Mailbox.java +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * Represents a single e-mail address. - * - * - */ -public class Mailbox extends Address { - private DomainList route; - private String localPart; - private String domain; - - /** - * Creates a mailbox without a route. Routes are obsolete. - * @param localPart The part of the e-mail address to the left of the "@". - * @param domain The part of the e-mail address to the right of the "@". - */ - public Mailbox(String localPart, String domain) { - this(null, localPart, domain); - } - - /** - * Creates a mailbox with a route. Routes are obsolete. - * @param route The zero or more domains that make up the route. Can be null. - * @param localPart The part of the e-mail address to the left of the "@". - * @param domain The part of the e-mail address to the right of the "@". - */ - public Mailbox(DomainList route, String localPart, String domain) { - this.route = route; - this.localPart = localPart; - this.domain = domain; - } - - /** - * Returns the route list. - */ - public DomainList getRoute() { - return route; - } - - /** - * Returns the left part of the e-mail address - * (before "@"). - */ - public String getLocalPart() { - return localPart; - } - - /** - * Returns the right part of the e-mail address - * (after "@"). - */ - public String getDomain() { - return domain; - } - - /** - * Formats the address as a string, not including - * the route. - * - * @see #getAddressString(boolean) - */ - public String getAddressString() { - return getAddressString(false); - } - - /** - * Note that this value may not be usable - * for transport purposes, only display purposes. - * - * For example, if the unparsed address was - * - * <"Joe Cheng"@joecheng.com> - * - * this method would return - * - * - * - * which is not valid for transport; the local part - * would need to be re-quoted. - * - * @param includeRoute true if the route should be included if it exists. - */ - public String getAddressString(boolean includeRoute) { - return "<" + (!includeRoute || route == null ? "" : route.toRouteString() + ":") - + localPart - + (domain == null ? "" : "@") - + domain + ">"; - } - - protected final void doAddMailboxesTo(ArrayList results) { - results.add(this); - } - - public String toString() { - return getAddressString(); - } -} diff --git a/src/org/apache/james/mime4j/field/address/MailboxList.java b/src/org/apache/james/mime4j/field/address/MailboxList.java deleted file mode 100644 index b25264da3..000000000 --- a/src/org/apache/james/mime4j/field/address/MailboxList.java +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -import java.util.ArrayList; - -/** - * An immutable, random-access list of Mailbox objects. - * - * - */ -public class MailboxList { - - private ArrayList mailboxes; - - /** - * @param mailboxes An ArrayList that contains only Mailbox objects. - * @param dontCopy true iff it is not possible for the mailboxes ArrayList to be modified by someone else. - */ - public MailboxList(ArrayList mailboxes, boolean dontCopy) { - if (mailboxes != null) - this.mailboxes = (dontCopy ? mailboxes : (ArrayList) mailboxes.clone()); - else - this.mailboxes = new ArrayList(0); - } - - /** - * The number of elements in this list. - */ - public int size() { - return mailboxes.size(); - } - - /** - * Gets an address. - */ - public Mailbox get(int index) { - if (0 > index || size() <= index) - throw new IndexOutOfBoundsException(); - return (Mailbox) mailboxes.get(index); - } - - /** - * Dumps a representation of this mailbox list to - * stdout, for debugging purposes. - */ - public void print() { - for (int i = 0; i < size(); i++) { - Mailbox mailbox = get(i); - System.out.println(mailbox.toString()); - } - } - -} diff --git a/src/org/apache/james/mime4j/field/address/NamedMailbox.java b/src/org/apache/james/mime4j/field/address/NamedMailbox.java deleted file mode 100644 index dea0d821c..000000000 --- a/src/org/apache/james/mime4j/field/address/NamedMailbox.java +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address; - -/** - * A Mailbox that has a name/description. - * - * - */ -public class NamedMailbox extends Mailbox { - private String name; - - /** - * @see Mailbox#Mailbox(String, String) - */ - public NamedMailbox(String name, String localPart, String domain) { - super(localPart, domain); - this.name = name; - } - - /** - * @see Mailbox#Mailbox(DomainList, String, String) - */ - public NamedMailbox(String name, DomainList route, String localPart, String domain) { - super(route, localPart, domain); - this.name = name; - } - - /** - * Creates a named mailbox based on an unnamed mailbox. - */ - public NamedMailbox(String name, Mailbox baseMailbox) { - super(baseMailbox.getRoute(), baseMailbox.getLocalPart(), baseMailbox.getDomain()); - this.name = name; - } - - /** - * Returns the name of the mailbox. - */ - public String getName() { - return this.name; - } - - /** - * Same features (or problems) as Mailbox.getAddressString(boolean), - * only more so. - * - * @see Mailbox#getAddressString(boolean) - */ - public String getAddressString(boolean includeRoute) { - return (name == null ? "" : name + " ") + super.getAddressString(includeRoute); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java deleted file mode 100644 index 4d56d000b..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTaddr_spec.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTaddr_spec extends SimpleNode { - public ASTaddr_spec(int id) { - super(id); - } - - public ASTaddr_spec(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java deleted file mode 100644 index 47bdeda8e..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTaddress.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTaddress extends SimpleNode { - public ASTaddress(int id) { - super(id); - } - - public ASTaddress(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java deleted file mode 100644 index 737840e38..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTaddress_list.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTaddress_list extends SimpleNode { - public ASTaddress_list(int id) { - super(id); - } - - public ASTaddress_list(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java b/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java deleted file mode 100644 index 8cb8f421f..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTangle_addr.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTangle_addr extends SimpleNode { - public ASTangle_addr(int id) { - super(id); - } - - public ASTangle_addr(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java b/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java deleted file mode 100644 index b52664386..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTdomain.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTdomain extends SimpleNode { - public ASTdomain(int id) { - super(id); - } - - public ASTdomain(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java b/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java deleted file mode 100644 index f6017b9fc..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTgroup_body.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTgroup_body extends SimpleNode { - public ASTgroup_body(int id) { - super(id); - } - - public ASTgroup_body(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java b/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java deleted file mode 100644 index 5c244fa3e..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTlocal_part.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTlocal_part extends SimpleNode { - public ASTlocal_part(int id) { - super(id); - } - - public ASTlocal_part(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java b/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java deleted file mode 100644 index aeb469da1..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTmailbox.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTmailbox extends SimpleNode { - public ASTmailbox(int id) { - super(id); - } - - public ASTmailbox(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java b/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java deleted file mode 100644 index 846c73167..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTname_addr.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTname_addr extends SimpleNode { - public ASTname_addr(int id) { - super(id); - } - - public ASTname_addr(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java b/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java deleted file mode 100644 index 7d711c529..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTphrase.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTphrase extends SimpleNode { - public ASTphrase(int id) { - super(id); - } - - public ASTphrase(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTroute.java b/src/org/apache/james/mime4j/field/address/parser/ASTroute.java deleted file mode 100644 index 54ea11523..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ASTroute.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. ASTroute.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class ASTroute extends SimpleNode { - public ASTroute(int id) { - super(id); - } - - public ASTroute(AddressListParser p, int id) { - super(p, id); - } - - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java deleted file mode 100644 index 6cf08ac1d..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java +++ /dev/null @@ -1,977 +0,0 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParser.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants, AddressListParserConstants {/*@bgen(jjtree)*/ - protected JJTAddressListParserState jjtree = new JJTAddressListParserState();public static void main(String args[]) throws ParseException { - while (true) { - try { - AddressListParser parser = new AddressListParser(System.in); - parser.parseLine(); - ((SimpleNode)parser.jjtree.rootNode()).dump("> "); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - private static void log(String msg) { - System.out.print(msg); - } - - public ASTaddress_list parse() throws ParseException { - try { - parseAll(); - return (ASTaddress_list)jjtree.rootNode(); - } catch (TokenMgrError tme) { - throw new ParseException(tme.getMessage()); - } - } - - - void jjtreeOpenNodeScope(Node n) { - ((SimpleNode)n).firstToken = getToken(1); - } - - void jjtreeCloseNodeScope(Node n) { - ((SimpleNode)n).lastToken = getToken(0); - } - - final public void parseLine() throws ParseException { - address_list(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 1: - jj_consume_token(1); - break; - default: - jj_la1[0] = jj_gen; - ; - } - jj_consume_token(2); - } - - final public void parseAll() throws ParseException { - address_list(); - jj_consume_token(0); - } - - final public void address_list() throws ParseException { - /*@bgen(jjtree) address_list */ - ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - address(); - break; - default: - jj_la1[1] = jj_gen; - ; - } - label_1: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - ; - break; - default: - jj_la1[2] = jj_gen; - break label_1; - } - jj_consume_token(3); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - address(); - break; - default: - jj_la1[3] = jj_gen; - ; - } - } - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void address() throws ParseException { - /*@bgen(jjtree) address */ - ASTaddress jjtn000 = new ASTaddress(JJTADDRESS); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - if (jj_2_1(2147483647)) { - addr_spec(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - angle_addr(); - break; - case DOTATOM: - case QUOTEDSTRING: - phrase(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - group_body(); - break; - case 6: - angle_addr(); - break; - default: - jj_la1[4] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - break; - default: - jj_la1[5] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void mailbox() throws ParseException { - /*@bgen(jjtree) mailbox */ - ASTmailbox jjtn000 = new ASTmailbox(JJTMAILBOX); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - if (jj_2_2(2147483647)) { - addr_spec(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - angle_addr(); - break; - case DOTATOM: - case QUOTEDSTRING: - name_addr(); - break; - default: - jj_la1[6] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void name_addr() throws ParseException { - /*@bgen(jjtree) name_addr */ - ASTname_addr jjtn000 = new ASTname_addr(JJTNAME_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - phrase(); - angle_addr(); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void group_body() throws ParseException { - /*@bgen(jjtree) group_body */ - ASTgroup_body jjtn000 = new ASTgroup_body(JJTGROUP_BODY); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - jj_consume_token(4); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - mailbox(); - break; - default: - jj_la1[7] = jj_gen; - ; - } - label_2: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - ; - break; - default: - jj_la1[8] = jj_gen; - break label_2; - } - jj_consume_token(3); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 6: - case DOTATOM: - case QUOTEDSTRING: - mailbox(); - break; - default: - jj_la1[9] = jj_gen; - ; - } - } - jj_consume_token(5); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void angle_addr() throws ParseException { - /*@bgen(jjtree) angle_addr */ - ASTangle_addr jjtn000 = new ASTangle_addr(JJTANGLE_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - jj_consume_token(6); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 8: - route(); - break; - default: - jj_la1[10] = jj_gen; - ; - } - addr_spec(); - jj_consume_token(7); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void route() throws ParseException { - /*@bgen(jjtree) route */ - ASTroute jjtn000 = new ASTroute(JJTROUTE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - jj_consume_token(8); - domain(); - label_3: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - case 8: - ; - break; - default: - jj_la1[11] = jj_gen; - break label_3; - } - label_4: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 3: - ; - break; - default: - jj_la1[12] = jj_gen; - break label_4; - } - jj_consume_token(3); - } - jj_consume_token(8); - domain(); - } - jj_consume_token(4); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void phrase() throws ParseException { - /*@bgen(jjtree) phrase */ - ASTphrase jjtn000 = new ASTphrase(JJTPHRASE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - label_5: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - jj_consume_token(DOTATOM); - break; - case QUOTEDSTRING: - jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[13] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - case QUOTEDSTRING: - ; - break; - default: - jj_la1[14] = jj_gen; - break label_5; - } - } - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void addr_spec() throws ParseException { - /*@bgen(jjtree) addr_spec */ - ASTaddr_spec jjtn000 = new ASTaddr_spec(JJTADDR_SPEC); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); - try { - local_part(); - jj_consume_token(8); - domain(); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void local_part() throws ParseException { - /*@bgen(jjtree) local_part */ - ASTlocal_part jjtn000 = new ASTlocal_part(JJTLOCAL_PART); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000);Token t; - try { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - t = jj_consume_token(DOTATOM); - break; - case QUOTEDSTRING: - t = jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[15] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - label_6: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - case DOTATOM: - case QUOTEDSTRING: - ; - break; - default: - jj_la1[16] = jj_gen; - break label_6; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - t = jj_consume_token(9); - break; - default: - jj_la1[17] = jj_gen; - ; - } - if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING) - {if (true) throw new ParseException("Words in local part must be separated by '.'");} - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - t = jj_consume_token(DOTATOM); - break; - case QUOTEDSTRING: - t = jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[18] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final public void domain() throws ParseException { - /*@bgen(jjtree) domain */ - ASTdomain jjtn000 = new ASTdomain(JJTDOMAIN); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000);Token t; - try { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOTATOM: - t = jj_consume_token(DOTATOM); - label_7: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - case DOTATOM: - ; - break; - default: - jj_la1[19] = jj_gen; - break label_7; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 9: - t = jj_consume_token(9); - break; - default: - jj_la1[20] = jj_gen; - ; - } - if (t.image.charAt(t.image.length() - 1) != '.') - {if (true) throw new ParseException("Atoms in domain names must be separated by '.'");} - t = jj_consume_token(DOTATOM); - } - break; - case DOMAINLITERAL: - jj_consume_token(DOMAINLITERAL); - break; - default: - jj_la1[21] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } - } - - final private boolean jj_2_1(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_1(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(0, xla); } - } - - final private boolean jj_2_2(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_2(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(1, xla); } - } - - final private boolean jj_3R_11() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(9)) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_scan_token(14)) { - jj_scanpos = xsp; - if (jj_scan_token(31)) return true; - } - return false; - } - - final private boolean jj_3R_13() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(9)) jj_scanpos = xsp; - if (jj_scan_token(DOTATOM)) return true; - return false; - } - - final private boolean jj_3R_8() { - if (jj_3R_9()) return true; - if (jj_scan_token(8)) return true; - if (jj_3R_10()) return true; - return false; - } - - final private boolean jj_3_1() { - if (jj_3R_8()) return true; - return false; - } - - final private boolean jj_3R_12() { - if (jj_scan_token(DOTATOM)) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_13()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_10() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_12()) { - jj_scanpos = xsp; - if (jj_scan_token(18)) return true; - } - return false; - } - - final private boolean jj_3_2() { - if (jj_3R_8()) return true; - return false; - } - - final private boolean jj_3R_9() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(14)) { - jj_scanpos = xsp; - if (jj_scan_token(31)) return true; - } - while (true) { - xsp = jj_scanpos; - if (jj_3R_11()) { jj_scanpos = xsp; break; } - } - return false; - } - - public AddressListParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private Token jj_scanpos, jj_lastpos; - private int jj_la; - public boolean lookingAhead = false; - private boolean jj_semLA; - private int jj_gen; - final private int[] jj_la1 = new int[22]; - static private int[] jj_la1_0; - static private int[] jj_la1_1; - static { - jj_la1_0(); - jj_la1_1(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0x2,0x80004040,0x8,0x80004040,0x50,0x80004040,0x80004040,0x80004040,0x8,0x80004040,0x100,0x108,0x8,0x80004000,0x80004000,0x80004000,0x80004200,0x200,0x80004000,0x4200,0x200,0x44000,}; - } - private static void jj_la1_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; - } - final private JJCalls[] jj_2_rtns = new JJCalls[2]; - private boolean jj_rescan = false; - private int jj_gc = 0; - - public AddressListParser(java.io.InputStream stream) { - this(stream, null); - } - public AddressListParser(java.io.InputStream stream, String encoding) { - try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source = new AddressListParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - public void ReInit(java.io.InputStream stream, String encoding) { - try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public AddressListParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new AddressListParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public AddressListParser(AddressListParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(AddressListParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 22; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - if (++jj_gc > 100) { - jj_gc = 0; - for (int i = 0; i < jj_2_rtns.length; i++) { - JJCalls c = jj_2_rtns[i]; - while (c != null) { - if (c.gen < jj_gen) c.first = null; - c = c.next; - } - } - } - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - static private final class LookaheadSuccess extends java.lang.Error { } - final private LookaheadSuccess jj_ls = new LookaheadSuccess(); - final private boolean jj_scan_token(int kind) { - if (jj_scanpos == jj_lastpos) { - jj_la--; - if (jj_scanpos.next == null) { - jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); - } else { - jj_lastpos = jj_scanpos = jj_scanpos.next; - } - } else { - jj_scanpos = jj_scanpos.next; - } - if (jj_rescan) { - int i = 0; Token tok = token; - while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; } - if (tok != null) jj_add_error_token(kind, i); - } - if (jj_scanpos.kind != kind) return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; - return false; - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = lookingAhead ? jj_scanpos : token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private java.util.Vector jj_expentries = new java.util.Vector(); - private int[] jj_expentry; - private int jj_kind = -1; - private int[] jj_lasttokens = new int[100]; - private int jj_endpos; - - private void jj_add_error_token(int kind, int pos) { - if (pos >= 100) return; - if (pos == jj_endpos + 1) { - jj_lasttokens[jj_endpos++] = kind; - } else if (jj_endpos != 0) { - jj_expentry = new int[jj_endpos]; - for (int i = 0; i < jj_endpos; i++) { - jj_expentry[i] = jj_lasttokens[i]; - } - boolean exists = false; - for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) { - int[] oldentry = (int[])(e.nextElement()); - if (oldentry.length == jj_expentry.length) { - exists = true; - for (int i = 0; i < jj_expentry.length; i++) { - if (oldentry[i] != jj_expentry[i]) { - exists = false; - break; - } - } - if (exists) break; - } - } - if (!exists) jj_expentries.addElement(jj_expentry); - if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind; - } - } - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[34]; - for (int i = 0; i < 34; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 22; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1< jj_gen) { - jj_la = p.arg; jj_lastpos = jj_scanpos = p.first; - switch (i) { - case 0: jj_3_1(); break; - case 1: jj_3_2(); break; - } - } - p = p.next; - } while (p != null); - } catch(LookaheadSuccess ls) { } - } - jj_rescan = false; - } - - final private void jj_save(int index, int xla) { - JJCalls p = jj_2_rtns[index]; - while (p.gen > jj_gen) { - if (p.next == null) { p = p.next = new JJCalls(); break; } - p = p.next; - } - p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla; - } - - static final class JJCalls { - int gen; - Token first; - int arg; - JJCalls next; - } - -} diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj b/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj deleted file mode 100644 index 685988634..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj +++ /dev/null @@ -1,595 +0,0 @@ -/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParser.jj */ -/*@egen*//**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - - -/** - * RFC2822 address list parser. - * - * Created 9/17/2004 - * by Joe Cheng - */ - -options { - STATIC=false; - LOOKAHEAD=1; - //DEBUG_PARSER=true; - //DEBUG_TOKEN_MANAGER=true; -} - -PARSER_BEGIN(AddressListParser) -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants/*@egen*/ {/*@bgen(jjtree)*/ - protected JJTAddressListParserState jjtree = new JJTAddressListParserState(); - -/*@egen*/ - public static void main(String args[]) throws ParseException { - while (true) { - try { - AddressListParser parser = new AddressListParser(System.in); - parser.parseLine(); - ((SimpleNode)parser.jjtree.rootNode()).dump("> "); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - private static void log(String msg) { - System.out.print(msg); - } - - public ASTaddress_list parse() throws ParseException { - try { - parseAll(); - return (ASTaddress_list)jjtree.rootNode(); - } catch (TokenMgrError tme) { - throw new ParseException(tme.getMessage()); - } - } - - - void jjtreeOpenNodeScope(Node n) { - ((SimpleNode)n).firstToken = getToken(1); - } - - void jjtreeCloseNodeScope(Node n) { - ((SimpleNode)n).lastToken = getToken(0); - } -} - -PARSER_END(AddressListParser) - -void parseLine() : -{} -{ - address_list() ["\r"] "\n" -} - -void parseAll() : -{} -{ - address_list() -} - -void address_list() : -{/*@bgen(jjtree) address_list */ - ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) address_list */ - try { -/*@egen*/ - [ address() ] - ( - "," - [ address() ] - )*/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void address() : -{/*@bgen(jjtree) address */ - ASTaddress jjtn000 = new ASTaddress(JJTADDRESS); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) address */ - try { -/*@egen*/ - LOOKAHEAD(2147483647) - addr_spec() -| angle_addr() -| ( phrase() (group_body() | angle_addr()) )/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void mailbox() : -{/*@bgen(jjtree) mailbox */ - ASTmailbox jjtn000 = new ASTmailbox(JJTMAILBOX); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) mailbox */ - try { -/*@egen*/ - LOOKAHEAD(2147483647) - addr_spec() -| angle_addr() -| name_addr()/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void name_addr() : -{/*@bgen(jjtree) name_addr */ - ASTname_addr jjtn000 = new ASTname_addr(JJTNAME_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) name_addr */ - try { -/*@egen*/ - phrase() angle_addr()/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void group_body() : -{/*@bgen(jjtree) group_body */ - ASTgroup_body jjtn000 = new ASTgroup_body(JJTGROUP_BODY); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) group_body */ - try { -/*@egen*/ - ":" - [ mailbox() ] - ( - "," - [ mailbox() ] - )* - ";"/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void angle_addr() : -{/*@bgen(jjtree) angle_addr */ - ASTangle_addr jjtn000 = new ASTangle_addr(JJTANGLE_ADDR); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) angle_addr */ - try { -/*@egen*/ - "<" [ route() ] addr_spec() ">"/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void route() : -{/*@bgen(jjtree) route */ - ASTroute jjtn000 = new ASTroute(JJTROUTE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) route */ - try { -/*@egen*/ - "@" domain() ( (",")* "@" domain() )* ":"/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void phrase() : -{/*@bgen(jjtree) phrase */ - ASTphrase jjtn000 = new ASTphrase(JJTPHRASE); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) phrase */ -try { -/*@egen*/ -( -| -)+/*@bgen(jjtree)*/ -} finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } -} -/*@egen*/ -} - -void addr_spec() : -{/*@bgen(jjtree) addr_spec */ - ASTaddr_spec jjtn000 = new ASTaddr_spec(JJTADDR_SPEC); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/} -{/*@bgen(jjtree) addr_spec */ - try { -/*@egen*/ - ( local_part() "@" domain() )/*@bgen(jjtree)*/ - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - throw (RuntimeException)jjte000; - } - if (jjte000 instanceof ParseException) { - throw (ParseException)jjte000; - } - throw (Error)jjte000; - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void local_part() : -{/*@bgen(jjtree) local_part */ - ASTlocal_part jjtn000 = new ASTlocal_part(JJTLOCAL_PART); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/ Token t; } -{/*@bgen(jjtree) local_part */ - try { -/*@egen*/ - ( t= | t= ) - ( [t="."] - { - if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING) - throw new ParseException("Words in local part must be separated by '.'"); - } - ( t= | t= ) - )*/*@bgen(jjtree)*/ - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -void domain() : -{/*@bgen(jjtree) domain */ - ASTdomain jjtn000 = new ASTdomain(JJTDOMAIN); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - jjtreeOpenNodeScope(jjtn000); -/*@egen*/ Token t; } -{/*@bgen(jjtree) domain */ - try { -/*@egen*/ - ( t= - ( [t="."] - { - if (t.image.charAt(t.image.length() - 1) != '.') - throw new ParseException("Atoms in domain names must be separated by '.'"); - } - t= - )* - ) -| /*@bgen(jjtree)*/ - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - jjtreeCloseNodeScope(jjtn000); - } - } -/*@egen*/ -} - -SPECIAL_TOKEN : -{ - < WS: ( [" ", "\t"] )+ > -} - -TOKEN : -{ - < #ALPHA: ["a" - "z", "A" - "Z"] > -| < #DIGIT: ["0" - "9"] > -| < #ATEXT: ( | - | "!" | "#" | "$" | "%" - | "&" | "'" | "*" | "+" - | "-" | "/" | "=" | "?" - | "^" | "_" | "`" | "{" - | "|" | "}" | "~" - )> -| < DOTATOM: ( | "." )* > -} - -TOKEN_MGR_DECLS : -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; -} - -MORE : -{ - // domain literal - "[" : INDOMAINLITERAL -} - - -MORE : -{ - < > { image.deleteCharAt(image.length() - 2); } -| < ~["[", "]", "\\"] > -} - - -TOKEN : -{ - < DOMAINLITERAL: "]" > { matchedToken.image = image.toString(); }: DEFAULT -} - -MORE : -{ - // starts a comment - "(" : INCOMMENT -} - - -SKIP : -{ - // ends a comment - < COMMENT: ")" > : DEFAULT - // if this is ever changed to not be a SKIP, need - // to make sure matchedToken.token = token.toString() - // is called. -} - - -MORE : -{ - < > { image.deleteCharAt(image.length() - 2); } -| "(" { commentNest = 1; } : NESTED_COMMENT -| < > -} - - -MORE : -{ - < > { image.deleteCharAt(image.length() - 2); } -| "(" { ++commentNest; } -| ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); } -| < > -} - - -// QUOTED STRINGS - -MORE : -{ - "\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING -} - - -MORE : -{ - < > { image.deleteCharAt(image.length() - 2); } -| < (~["\"", "\\"])+ > -} - - -TOKEN : -{ - < QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT -} - -// GLOBALS - -<*> -TOKEN : -{ - < #QUOTEDPAIR: "\\" > -| < #ANY: ~[] > -} - -// ERROR! -/* - -<*> -TOKEN : -{ - < UNEXPECTED_CHAR: > -} - -*/ \ No newline at end of file diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java deleted file mode 100644 index a21ad35db..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java +++ /dev/null @@ -1,76 +0,0 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserConstants.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public interface AddressListParserConstants { - - int EOF = 0; - int WS = 10; - int ALPHA = 11; - int DIGIT = 12; - int ATEXT = 13; - int DOTATOM = 14; - int DOMAINLITERAL = 18; - int COMMENT = 20; - int QUOTEDSTRING = 31; - int QUOTEDPAIR = 32; - int ANY = 33; - - int DEFAULT = 0; - int INDOMAINLITERAL = 1; - int INCOMMENT = 2; - int NESTED_COMMENT = 3; - int INQUOTEDSTRING = 4; - - String[] tokenImage = { - "", - "\"\\r\"", - "\"\\n\"", - "\",\"", - "\":\"", - "\";\"", - "\"<\"", - "\">\"", - "\"@\"", - "\".\"", - "", - "", - "", - "", - "", - "\"[\"", - "", - "", - "\"]\"", - "\"(\"", - "\")\"", - "", - "\"(\"", - "", - "", - "\"(\"", - "\")\"", - "", - "\"\\\"\"", - "", - "", - "\"\\\"\"", - "", - "", - }; - -} diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java deleted file mode 100644 index df8974a3b..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java +++ /dev/null @@ -1,1009 +0,0 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserTokenManager.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class AddressListParserTokenManager implements AddressListParserConstants -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 10: - return jjStopAtPos(0, 2); - case 13: - return jjStopAtPos(0, 1); - case 34: - return jjStopAtPos(0, 28); - case 40: - return jjStopAtPos(0, 19); - case 44: - return jjStopAtPos(0, 3); - case 46: - return jjStopAtPos(0, 9); - case 58: - return jjStopAtPos(0, 4); - case 59: - return jjStopAtPos(0, 5); - case 60: - return jjStopAtPos(0, 6); - case 62: - return jjStopAtPos(0, 7); - case 64: - return jjStopAtPos(0, 8); - case 91: - return jjStopAtPos(0, 15); - default : - return jjMoveNfa_0(1, 0); - } -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 1: - if ((0xa3ffacfa00000000L & l) != 0L) - { - if (kind > 14) - kind = 14; - jjCheckNAdd(2); - } - else if ((0x100000200L & l) != 0L) - { - if (kind > 10) - kind = 10; - jjCheckNAdd(0); - } - break; - case 0: - if ((0x100000200L & l) == 0L) - break; - kind = 10; - jjCheckNAdd(0); - break; - case 2: - if ((0xa3ffecfa00000000L & l) == 0L) - break; - if (kind > 14) - kind = 14; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 1: - case 2: - if ((0x7fffffffc7fffffeL & l) == 0L) - break; - if (kind > 14) - kind = 14; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_2(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_2(int pos, long active0) -{ - return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_2(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_2(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_2() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 22); - case 41: - return jjStopAtPos(0, 20); - default : - return jjMoveNfa_2(0, 0); - } -} -static final long[] jjbitVec0 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_2(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 23) - kind = 23; - break; - case 1: - if (kind > 21) - kind = 21; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 23) - kind = 23; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 21) - kind = 21; - break; - case 2: - if (kind > 23) - kind = 23; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 23) - kind = 23; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 21) - kind = 21; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_4(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_4(int pos, long active0) -{ - return jjMoveNfa_4(jjStopStringLiteralDfa_4(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_4(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_4(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_4() -{ - switch(curChar) - { - case 34: - return jjStopAtPos(0, 31); - default : - return jjMoveNfa_4(0, 0); - } -} -private final int jjMoveNfa_4(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((0xfffffffbffffffffL & l) == 0L) - break; - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - break; - case 1: - if (kind > 29) - kind = 29; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0xffffffffefffffffL & l) != 0L) - { - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - } - else if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 29) - kind = 29; - break; - case 2: - if ((0xffffffffefffffffL & l) == 0L) - break; - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((jjbitVec0[i2] & l2) == 0L) - break; - if (kind > 30) - kind = 30; - jjCheckNAdd(2); - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 29) - kind = 29; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_3(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_3(int pos, long active0) -{ - return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_3(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_3(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_3() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 25); - case 41: - return jjStopAtPos(0, 26); - default : - return jjMoveNfa_3(0, 0); - } -} -private final int jjMoveNfa_3(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 27) - kind = 27; - break; - case 1: - if (kind > 24) - kind = 24; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 27) - kind = 27; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 24) - kind = 24; - break; - case 2: - if (kind > 27) - kind = 27; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 27) - kind = 27; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 24) - kind = 24; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_1(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_1(int pos, long active0) -{ - return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_1(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_1(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_1() -{ - switch(curChar) - { - case 93: - return jjStopAtPos(0, 18); - default : - return jjMoveNfa_1(0, 0); - } -} -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 17) - kind = 17; - break; - case 1: - if (kind > 16) - kind = 16; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0xffffffffc7ffffffL & l) != 0L) - { - if (kind > 17) - kind = 17; - } - else if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 16) - kind = 16; - break; - case 2: - if ((0xffffffffc7ffffffL & l) != 0L && kind > 17) - kind = 17; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 17) - kind = 17; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 16) - kind = 16; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { -}; -public static final String[] jjstrLiteralImages = { -"", "\15", "\12", "\54", "\72", "\73", "\74", "\76", "\100", "\56", null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "INDOMAINLITERAL", - "INCOMMENT", - "NESTED_COMMENT", - "INQUOTEDSTRING", -}; -public static final int[] jjnewLexState = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, 2, 0, -1, 3, -1, -1, - -1, -1, -1, 4, -1, -1, 0, -1, -1, -}; -static final long[] jjtoToken = { - 0x800443ffL, -}; -static final long[] jjtoSkip = { - 0x100400L, -}; -static final long[] jjtoSpecial = { - 0x400L, -}; -static final long[] jjtoMore = { - 0x7feb8000L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[3]; -private final int[] jjstateSet = new int[6]; -StringBuffer image; -int jjimageLen; -int lengthOfMatch; -protected char curChar; -public AddressListParserTokenManager(SimpleCharStream stream){ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public AddressListParserTokenManager(SimpleCharStream stream, int lexState){ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 3; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 5 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - return matchedToken; - } - image = null; - jjimageLen = 0; - - for (;;) - { - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - break; - case 1: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - break; - case 2: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_2(); - break; - case 3: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_3(); - break; - case 4: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_4(); - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - TokenLexicalActions(matchedToken); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (specialToken == null) - specialToken = matchedToken; - else - { - matchedToken.specialToken = specialToken; - specialToken = (specialToken.next = matchedToken); - } - } - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - MoreLexicalActions(); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - curPos = 0; - jjmatchedKind = 0x7fffffff; - try { - curChar = input_stream.readChar(); - continue; - } - catch (java.io.IOException e1) { } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } -} - -void MoreLexicalActions() -{ - jjimageLen += (lengthOfMatch = jjmatchedPos + 1); - switch(jjmatchedKind) - { - case 16 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 21 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 22 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - commentNest = 1; - break; - case 24 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 25 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - ++commentNest; - break; - case 26 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); - break; - case 28 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 1); - break; - case 29 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - default : - break; - } -} -void TokenLexicalActions(Token matchedToken) -{ - switch(jjmatchedKind) - { - case 18 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - matchedToken.image = image.toString(); - break; - case 31 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - matchedToken.image = image.substring(0, image.length() - 1); - break; - default : - break; - } -} -} diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java deleted file mode 100644 index 5987f19d8..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java */ - -package org.apache.james.mime4j.field.address.parser; - -public interface AddressListParserTreeConstants -{ - public int JJTVOID = 0; - public int JJTADDRESS_LIST = 1; - public int JJTADDRESS = 2; - public int JJTMAILBOX = 3; - public int JJTNAME_ADDR = 4; - public int JJTGROUP_BODY = 5; - public int JJTANGLE_ADDR = 6; - public int JJTROUTE = 7; - public int JJTPHRASE = 8; - public int JJTADDR_SPEC = 9; - public int JJTLOCAL_PART = 10; - public int JJTDOMAIN = 11; - - - public String[] jjtNodeName = { - "void", - "address_list", - "address", - "mailbox", - "name_addr", - "group_body", - "angle_addr", - "route", - "phrase", - "addr_spec", - "local_part", - "domain", - }; -} diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java deleted file mode 100644 index 8ec2fe7d2..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java */ - -package org.apache.james.mime4j.field.address.parser; - -public interface AddressListParserVisitor -{ - public Object visit(SimpleNode node, Object data); - public Object visit(ASTaddress_list node, Object data); - public Object visit(ASTaddress node, Object data); - public Object visit(ASTmailbox node, Object data); - public Object visit(ASTname_addr node, Object data); - public Object visit(ASTgroup_body node, Object data); - public Object visit(ASTangle_addr node, Object data); - public Object visit(ASTroute node, Object data); - public Object visit(ASTphrase node, Object data); - public Object visit(ASTaddr_spec node, Object data); - public Object visit(ASTlocal_part node, Object data); - public Object visit(ASTdomain node, Object data); -} diff --git a/src/org/apache/james/mime4j/field/address/parser/BaseNode.java b/src/org/apache/james/mime4j/field/address/parser/BaseNode.java deleted file mode 100644 index 42fe3db0c..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/BaseNode.java +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.address.parser; - -import org.apache.james.mime4j.field.address.parser.Node; -import org.apache.james.mime4j.field.address.parser.Token; - -public abstract class BaseNode implements Node { - - public Token firstToken; - public Token lastToken; - -} \ No newline at end of file diff --git a/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java b/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java deleted file mode 100644 index cca539483..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java +++ /dev/null @@ -1,123 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java */ - -package org.apache.james.mime4j.field.address.parser; - -class JJTAddressListParserState { - private java.util.Stack nodes; - private java.util.Stack marks; - - private int sp; // number of nodes on stack - private int mk; // current mark - private boolean node_created; - - JJTAddressListParserState() { - nodes = new java.util.Stack(); - marks = new java.util.Stack(); - sp = 0; - mk = 0; - } - - /* Determines whether the current node was actually closed and - pushed. This should only be called in the final user action of a - node scope. */ - boolean nodeCreated() { - return node_created; - } - - /* Call this to reinitialize the node stack. It is called - automatically by the parser's ReInit() method. */ - void reset() { - nodes.removeAllElements(); - marks.removeAllElements(); - sp = 0; - mk = 0; - } - - /* Returns the root node of the AST. It only makes sense to call - this after a successful parse. */ - Node rootNode() { - return (Node)nodes.elementAt(0); - } - - /* Pushes a node on to the stack. */ - void pushNode(Node n) { - nodes.push(n); - ++sp; - } - - /* Returns the node on the top of the stack, and remove it from the - stack. */ - Node popNode() { - if (--sp < mk) { - mk = ((Integer)marks.pop()).intValue(); - } - return (Node)nodes.pop(); - } - - /* Returns the node currently on the top of the stack. */ - Node peekNode() { - return (Node)nodes.peek(); - } - - /* Returns the number of children on the stack in the current node - scope. */ - int nodeArity() { - return sp - mk; - } - - - void clearNodeScope(Node n) { - while (sp > mk) { - popNode(); - } - mk = ((Integer)marks.pop()).intValue(); - } - - - void openNodeScope(Node n) { - marks.push(new Integer(mk)); - mk = sp; - n.jjtOpen(); - } - - - /* A definite node is constructed from a specified number of - children. That number of nodes are popped from the stack and - made the children of the definite node. Then the definite node - is pushed on to the stack. */ - void closeNodeScope(Node n, int num) { - mk = ((Integer)marks.pop()).intValue(); - while (num-- > 0) { - Node c = popNode(); - c.jjtSetParent(n); - n.jjtAddChild(c, num); - } - n.jjtClose(); - pushNode(n); - node_created = true; - } - - - /* A conditional node is constructed if its condition is true. All - the nodes that have been pushed since the node was opened are - made children of the the conditional node, which is then pushed - on to the stack. If the condition is false the node is not - constructed and they are left on the stack. */ - void closeNodeScope(Node n, boolean condition) { - if (condition) { - int a = nodeArity(); - mk = ((Integer)marks.pop()).intValue(); - while (a-- > 0) { - Node c = popNode(); - c.jjtSetParent(n); - n.jjtAddChild(c, a); - } - n.jjtClose(); - pushNode(n); - node_created = true; - } else { - mk = ((Integer)marks.pop()).intValue(); - node_created = false; - } - } -} diff --git a/src/org/apache/james/mime4j/field/address/parser/Node.java b/src/org/apache/james/mime4j/field/address/parser/Node.java deleted file mode 100644 index 158892016..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/Node.java +++ /dev/null @@ -1,37 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. Node.java */ - -package org.apache.james.mime4j.field.address.parser; - -/* All AST nodes must implement this interface. It provides basic - machinery for constructing the parent and child relationships - between nodes. */ - -public interface Node { - - /** This method is called after the node has been made the current - node. It indicates that child nodes can now be added to it. */ - public void jjtOpen(); - - /** This method is called after all the child nodes have been - added. */ - public void jjtClose(); - - /** This pair of methods are used to inform the node of its - parent. */ - public void jjtSetParent(Node n); - public Node jjtGetParent(); - - /** This method tells the node to add its argument to the node's - list of children. */ - public void jjtAddChild(Node n, int i); - - /** This method returns a child node. The children are numbered - from zero, left to right. */ - public Node jjtGetChild(int i); - - /** Return the number of children the node has. */ - public int jjtGetNumChildren(); - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data); -} diff --git a/src/org/apache/james/mime4j/field/address/parser/ParseException.java b/src/org/apache/james/mime4j/field/address/parser/ParseException.java deleted file mode 100644 index 939c6cfed..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/ParseException.java +++ /dev/null @@ -1,207 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - StringBuffer expected = new StringBuffer(); - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} diff --git a/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java deleted file mode 100644 index 957bbeabc..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java +++ /dev/null @@ -1,454 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} diff --git a/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java b/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java deleted file mode 100644 index 9bf537e60..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java +++ /dev/null @@ -1,87 +0,0 @@ -/* Generated By:JJTree: Do not edit this line. SimpleNode.java */ - -package org.apache.james.mime4j.field.address.parser; - -public class SimpleNode extends org.apache.james.mime4j.field.address.parser.BaseNode implements Node { - protected Node parent; - protected Node[] children; - protected int id; - protected AddressListParser parser; - - public SimpleNode(int i) { - id = i; - } - - public SimpleNode(AddressListParser p, int i) { - this(i); - parser = p; - } - - public void jjtOpen() { - } - - public void jjtClose() { - } - - public void jjtSetParent(Node n) { parent = n; } - public Node jjtGetParent() { return parent; } - - public void jjtAddChild(Node n, int i) { - if (children == null) { - children = new Node[i + 1]; - } else if (i >= children.length) { - Node c[] = new Node[i + 1]; - System.arraycopy(children, 0, c, 0, children.length); - children = c; - } - children[i] = n; - } - - public Node jjtGetChild(int i) { - return children[i]; - } - - public int jjtGetNumChildren() { - return (children == null) ? 0 : children.length; - } - - /** Accept the visitor. **/ - public Object jjtAccept(AddressListParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - /** Accept the visitor. **/ - public Object childrenAccept(AddressListParserVisitor visitor, Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - children[i].jjtAccept(visitor, data); - } - } - return data; - } - - /* You can override these two methods in subclasses of SimpleNode to - customize the way the node appears when the tree is dumped. If - your output uses more than one line you should override - toString(String), otherwise overriding toString() is probably all - you need to do. */ - - public String toString() { return AddressListParserTreeConstants.jjtNodeName[id]; } - public String toString(String prefix) { return prefix + toString(); } - - /* Override this method if you want to customize how the node dumps - out its children. */ - - public void dump(String prefix) { - System.out.println(toString(prefix)); - if (children != null) { - for (int i = 0; i < children.length; ++i) { - SimpleNode n = (SimpleNode)children[i]; - if (n != null) { - n.dump(prefix + " "); - } - } - } - } -} - diff --git a/src/org/apache/james/mime4j/field/address/parser/Token.java b/src/org/apache/james/mime4j/field/address/parser/Token.java deleted file mode 100644 index 0228aac3e..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/Token.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} diff --git a/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java deleted file mode 100644 index c06a44cf3..000000000 --- a/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java +++ /dev/null @@ -1,148 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.address.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java deleted file mode 100644 index 64e829a51..000000000 --- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java +++ /dev/null @@ -1,267 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ContentTypeParser.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -import java.util.ArrayList; - -public class ContentTypeParser implements ContentTypeParserConstants { - - private String type; - private String subtype; - private ArrayList paramNames = new ArrayList(); - private ArrayList paramValues = new ArrayList(); - - public String getType() { return type; } - public String getSubType() { return subtype; } - public ArrayList getParamNames() { return paramNames; } - public ArrayList getParamValues() { return paramValues; } - - public static void main(String args[]) throws ParseException { - while (true) { - try { - ContentTypeParser parser = new ContentTypeParser(System.in); - parser.parseLine(); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - final public void parseLine() throws ParseException { - parse(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 1: - jj_consume_token(1); - break; - default: - jj_la1[0] = jj_gen; - ; - } - jj_consume_token(2); - } - - final public void parseAll() throws ParseException { - parse(); - jj_consume_token(0); - } - - final public void parse() throws ParseException { - Token type; - Token subtype; - type = jj_consume_token(ATOKEN); - jj_consume_token(3); - subtype = jj_consume_token(ATOKEN); - this.type = type.image; - this.subtype = subtype.image; - label_1: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - ; - break; - default: - jj_la1[1] = jj_gen; - break label_1; - } - jj_consume_token(4); - parameter(); - } - } - - final public void parameter() throws ParseException { - Token attrib; - String val; - attrib = jj_consume_token(ATOKEN); - jj_consume_token(5); - val = value(); - paramNames.add(attrib.image); - paramValues.add(val); - } - - final public String value() throws ParseException { - Token t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ATOKEN: - t = jj_consume_token(ATOKEN); - break; - case QUOTEDSTRING: - t = jj_consume_token(QUOTEDSTRING); - break; - default: - jj_la1[2] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return t.image;} - throw new Error("Missing return statement in function"); - } - - public ContentTypeParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private int jj_gen; - final private int[] jj_la1 = new int[3]; - static private int[] jj_la1_0; - static { - jj_la1_0(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0x2,0x10,0x280000,}; - } - - public ContentTypeParser(java.io.InputStream stream) { - this(stream, null); - } - public ContentTypeParser(java.io.InputStream stream, String encoding) { - try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source = new ContentTypeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - public void ReInit(java.io.InputStream stream, String encoding) { - try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public ContentTypeParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new ContentTypeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public ContentTypeParser(ContentTypeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - public void ReInit(ContentTypeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 3; i++) jj_la1[i] = -1; - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private java.util.Vector jj_expentries = new java.util.Vector(); - private int[] jj_expentry; - private int jj_kind = -1; - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[24]; - for (int i = 0; i < 24; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 3; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1<", - "\"\\r\"", - "\"\\n\"", - "\"/\"", - "\";\"", - "\"=\"", - "", - "\"(\"", - "\")\"", - "", - "\"(\"", - "", - "", - "\"(\"", - "\")\"", - "", - "\"\\\"\"", - "", - "", - "\"\\\"\"", - "", - "", - "", - "", - }; - -} diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java deleted file mode 100644 index 05d940db5..000000000 --- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java +++ /dev/null @@ -1,877 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ContentTypeParserTokenManager.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; -import java.util.ArrayList; - -public class ContentTypeParserTokenManager implements ContentTypeParserConstants -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 10: - return jjStartNfaWithStates_0(0, 2, 2); - case 13: - return jjStartNfaWithStates_0(0, 1, 2); - case 34: - return jjStopAtPos(0, 16); - case 40: - return jjStopAtPos(0, 7); - case 47: - return jjStopAtPos(0, 3); - case 59: - return jjStopAtPos(0, 4); - case 61: - return jjStopAtPos(0, 5); - default : - return jjMoveNfa_0(3, 0); - } -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -static final long[] jjbitVec0 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 3: - if ((0x3ff6cfafffffdffL & l) != 0L) - { - if (kind > 21) - kind = 21; - jjCheckNAdd(2); - } - else if ((0x100000200L & l) != 0L) - { - if (kind > 6) - kind = 6; - jjCheckNAdd(0); - } - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 20) - kind = 20; - jjCheckNAdd(1); - } - break; - case 0: - if ((0x100000200L & l) == 0L) - break; - kind = 6; - jjCheckNAdd(0); - break; - case 1: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(1); - break; - case 2: - if ((0x3ff6cfafffffdffL & l) == 0L) - break; - if (kind > 21) - kind = 21; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 3: - case 2: - if ((0xffffffffc7fffffeL & l) == 0L) - break; - kind = 21; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 3: - case 2: - if ((jjbitVec0[i2] & l2) == 0L) - break; - if (kind > 21) - kind = 21; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_1(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_1(int pos, long active0) -{ - return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_1(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_1(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_1() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 10); - case 41: - return jjStopAtPos(0, 8); - default : - return jjMoveNfa_1(0, 0); - } -} -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 11) - kind = 11; - break; - case 1: - if (kind > 9) - kind = 9; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 11) - kind = 11; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 9) - kind = 9; - break; - case 2: - if (kind > 11) - kind = 11; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 11) - kind = 11; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 9) - kind = 9; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_3(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_3(int pos, long active0) -{ - return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_3(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_3(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_3() -{ - switch(curChar) - { - case 34: - return jjStopAtPos(0, 19); - default : - return jjMoveNfa_3(0, 0); - } -} -private final int jjMoveNfa_3(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((0xfffffffbffffffffL & l) == 0L) - break; - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - break; - case 1: - if (kind > 17) - kind = 17; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0xffffffffefffffffL & l) != 0L) - { - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - } - else if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 17) - kind = 17; - break; - case 2: - if ((0xffffffffefffffffL & l) == 0L) - break; - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 2: - if ((jjbitVec0[i2] & l2) == 0L) - break; - if (kind > 18) - kind = 18; - jjCheckNAdd(2); - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 17) - kind = 17; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_2(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_2(int pos, long active0) -{ - return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_2(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_2(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_2() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 13); - case 41: - return jjStopAtPos(0, 14); - default : - return jjMoveNfa_2(0, 0); - } -} -private final int jjMoveNfa_2(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 15) - kind = 15; - break; - case 1: - if (kind > 12) - kind = 12; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 15) - kind = 15; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 12) - kind = 12; - break; - case 2: - if (kind > 15) - kind = 15; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 15) - kind = 15; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 12) - kind = 12; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { -}; -public static final String[] jjstrLiteralImages = { -"", "\15", "\12", "\57", "\73", "\75", null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "INCOMMENT", - "NESTED_COMMENT", - "INQUOTEDSTRING", -}; -public static final int[] jjnewLexState = { - -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, -1, -1, -1, -}; -static final long[] jjtoToken = { - 0x38003fL, -}; -static final long[] jjtoSkip = { - 0x140L, -}; -static final long[] jjtoSpecial = { - 0x40L, -}; -static final long[] jjtoMore = { - 0x7fe80L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[3]; -private final int[] jjstateSet = new int[6]; -StringBuffer image; -int jjimageLen; -int lengthOfMatch; -protected char curChar; -public ContentTypeParserTokenManager(SimpleCharStream stream){ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public ContentTypeParserTokenManager(SimpleCharStream stream, int lexState){ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 3; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 4 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - return matchedToken; - } - image = null; - jjimageLen = 0; - - for (;;) - { - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - break; - case 1: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - break; - case 2: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_2(); - break; - case 3: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_3(); - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - TokenLexicalActions(matchedToken); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (specialToken == null) - specialToken = matchedToken; - else - { - matchedToken.specialToken = specialToken; - specialToken = (specialToken.next = matchedToken); - } - } - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - MoreLexicalActions(); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - curPos = 0; - jjmatchedKind = 0x7fffffff; - try { - curChar = input_stream.readChar(); - continue; - } - catch (java.io.IOException e1) { } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } -} - -void MoreLexicalActions() -{ - jjimageLen += (lengthOfMatch = jjmatchedPos + 1); - switch(jjmatchedKind) - { - case 9 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 10 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - commentNest = 1; - break; - case 12 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 13 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - ++commentNest; - break; - case 14 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); - break; - case 16 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 1); - break; - case 17 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - default : - break; - } -} -void TokenLexicalActions(Token matchedToken) -{ - switch(jjmatchedKind) - { - case 19 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - matchedToken.image = image.substring(0, image.length() - 1); - break; - default : - break; - } -} -} diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java b/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java deleted file mode 100644 index 2c5dc8275..000000000 --- a/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java +++ /dev/null @@ -1,207 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - StringBuffer expected = new StringBuffer(); - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java deleted file mode 100644 index c139e4f38..000000000 --- a/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java +++ /dev/null @@ -1,454 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/Token.java b/src/org/apache/james/mime4j/field/contenttype/parser/Token.java deleted file mode 100644 index 5bef6cf02..000000000 --- a/src/org/apache/james/mime4j/field/contenttype/parser/Token.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java deleted file mode 100644 index 4a490efac..000000000 --- a/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java +++ /dev/null @@ -1,148 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.contenttype.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} diff --git a/src/org/apache/james/mime4j/field/datetime/DateTime.java b/src/org/apache/james/mime4j/field/datetime/DateTime.java deleted file mode 100644 index bf00ca753..000000000 --- a/src/org/apache/james/mime4j/field/datetime/DateTime.java +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.field.datetime; - -import org.apache.james.mime4j.field.datetime.parser.DateTimeParser; -import org.apache.james.mime4j.field.datetime.parser.ParseException; -import org.apache.james.mime4j.field.datetime.parser.TokenMgrError; - -import java.util.Date; -import java.util.Calendar; -import java.util.TimeZone; -import java.util.GregorianCalendar; -import java.io.StringReader; - -public class DateTime { - private final Date date; - private final int year; - private final int month; - private final int day; - private final int hour; - private final int minute; - private final int second; - private final int timeZone; - - public DateTime(String yearString, int month, int day, int hour, int minute, int second, int timeZone) { - this.year = convertToYear(yearString); - this.date = convertToDate(year, month, day, hour, minute, second, timeZone); - this.month = month; - this.day = day; - this.hour = hour; - this.minute = minute; - this.second = second; - this.timeZone = timeZone; - } - - private int convertToYear(String yearString) { - int year = Integer.parseInt(yearString); - switch (yearString.length()) { - case 1: - case 2: - if (year >= 0 && year < 50) - return 2000 + year; - else - return 1900 + year; - case 3: - return 1900 + year; - default: - return year; - } - } - - public static Date convertToDate(int year, int month, int day, int hour, int minute, int second, int timeZone) { - Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT+0")); - c.set(year, month - 1, day, hour, minute, second); - c.set(Calendar.MILLISECOND, 0); - - if (timeZone != Integer.MIN_VALUE) { - int minutes = ((timeZone / 100) * 60) + timeZone % 100; - c.add(Calendar.MINUTE, -1 * minutes); - } - - return c.getTime(); - } - - public Date getDate() { - return date; - } - - public int getYear() { - return year; - } - - public int getMonth() { - return month; - } - - public int getDay() { - return day; - } - - public int getHour() { - return hour; - } - - public int getMinute() { - return minute; - } - - public int getSecond() { - return second; - } - - public int getTimeZone() { - return timeZone; - } - - public void print() { - System.out.println(getYear() + " " + getMonth() + " " + getDay() + "; " + getHour() + " " + getMinute() + " " + getSecond() + " " + getTimeZone()); - } - - - public static DateTime parse(String dateString) throws ParseException { - try { - return new DateTimeParser(new StringReader(dateString)).parseAll(); - } - catch (TokenMgrError err) { - throw new ParseException(err.getMessage()); - } - } -} diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java deleted file mode 100644 index 94b517208..000000000 --- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java +++ /dev/null @@ -1,570 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. DateTimeParser.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -import org.apache.james.mime4j.field.datetime.DateTime; - -import java.util.Calendar; - -public class DateTimeParser implements DateTimeParserConstants { - private static final boolean ignoreMilitaryZoneOffset = true; - - public static void main(String args[]) throws ParseException { - while (true) { - try { - DateTimeParser parser = new DateTimeParser(System.in); - parser.parseLine(); - } catch (Exception x) { - x.printStackTrace(); - return; - } - } - } - - private static int parseDigits(Token token) { - return Integer.parseInt(token.image, 10); - } - - private static int getMilitaryZoneOffset(char c) { - if (ignoreMilitaryZoneOffset) - return 0; - - c = Character.toUpperCase(c); - - switch (c) { - case 'A': return 1; - case 'B': return 2; - case 'C': return 3; - case 'D': return 4; - case 'E': return 5; - case 'F': return 6; - case 'G': return 7; - case 'H': return 8; - case 'I': return 9; - case 'K': return 10; - case 'L': return 11; - case 'M': return 12; - - case 'N': return -1; - case 'O': return -2; - case 'P': return -3; - case 'Q': return -4; - case 'R': return -5; - case 'S': return -6; - case 'T': return -7; - case 'U': return -8; - case 'V': return -9; - case 'W': return -10; - case 'X': return -11; - case 'Y': return -12; - - case 'Z': return 0; - default: return 0; - } - } - - private static class Time { - private int hour; - private int minute; - private int second; - private int zone; - - public Time(int hour, int minute, int second, int zone) { - this.hour = hour; - this.minute = minute; - this.second = second; - this.zone = zone; - } - - public int getHour() { return hour; } - public int getMinute() { return minute; } - public int getSecond() { return second; } - public int getZone() { return zone; } - } - - private static class Date { - private String year; - private int month; - private int day; - - public Date(String year, int month, int day) { - this.year = year; - this.month = month; - this.day = day; - } - - public String getYear() { return year; } - public int getMonth() { return month; } - public int getDay() { return day; } - } - - final public DateTime parseLine() throws ParseException { - DateTime dt; - dt = date_time(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 1: - jj_consume_token(1); - break; - default: - jj_la1[0] = jj_gen; - ; - } - jj_consume_token(2); - {if (true) return dt;} - throw new Error("Missing return statement in function"); - } - - final public DateTime parseAll() throws ParseException { - DateTime dt; - dt = date_time(); - jj_consume_token(0); - {if (true) return dt;} - throw new Error("Missing return statement in function"); - } - - final public DateTime date_time() throws ParseException { - Date d; Time t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - day_of_week(); - jj_consume_token(3); - break; - default: - jj_la1[1] = jj_gen; - ; - } - d = date(); - t = time(); - {if (true) return new DateTime( - d.getYear(), - d.getMonth(), - d.getDay(), - t.getHour(), - t.getMinute(), - t.getSecond(), - t.getZone());} // time zone offset - - throw new Error("Missing return statement in function"); - } - - final public String day_of_week() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 4: - jj_consume_token(4); - break; - case 5: - jj_consume_token(5); - break; - case 6: - jj_consume_token(6); - break; - case 7: - jj_consume_token(7); - break; - case 8: - jj_consume_token(8); - break; - case 9: - jj_consume_token(9); - break; - case 10: - jj_consume_token(10); - break; - default: - jj_la1[2] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return token.image;} - throw new Error("Missing return statement in function"); - } - - final public Date date() throws ParseException { - int d, m; String y; - d = day(); - m = month(); - y = year(); - {if (true) return new Date(y, m, d);} - throw new Error("Missing return statement in function"); - } - - final public int day() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int month() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 11: - jj_consume_token(11); - {if (true) return 1;} - break; - case 12: - jj_consume_token(12); - {if (true) return 2;} - break; - case 13: - jj_consume_token(13); - {if (true) return 3;} - break; - case 14: - jj_consume_token(14); - {if (true) return 4;} - break; - case 15: - jj_consume_token(15); - {if (true) return 5;} - break; - case 16: - jj_consume_token(16); - {if (true) return 6;} - break; - case 17: - jj_consume_token(17); - {if (true) return 7;} - break; - case 18: - jj_consume_token(18); - {if (true) return 8;} - break; - case 19: - jj_consume_token(19); - {if (true) return 9;} - break; - case 20: - jj_consume_token(20); - {if (true) return 10;} - break; - case 21: - jj_consume_token(21); - {if (true) return 11;} - break; - case 22: - jj_consume_token(22); - {if (true) return 12;} - break; - default: - jj_la1[3] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - throw new Error("Missing return statement in function"); - } - - final public String year() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return t.image;} - throw new Error("Missing return statement in function"); - } - - final public Time time() throws ParseException { - int h, m, s=0, z; - h = hour(); - jj_consume_token(23); - m = minute(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 23: - jj_consume_token(23); - s = second(); - break; - default: - jj_la1[4] = jj_gen; - ; - } - z = zone(); - {if (true) return new Time(h, m, s, z);} - throw new Error("Missing return statement in function"); - } - - final public int hour() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int minute() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int second() throws ParseException { - Token t; - t = jj_consume_token(DIGITS); - {if (true) return parseDigits(t);} - throw new Error("Missing return statement in function"); - } - - final public int zone() throws ParseException { - Token t, u; int z; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case OFFSETDIR: - t = jj_consume_token(OFFSETDIR); - u = jj_consume_token(DIGITS); - z=parseDigits(u)*(t.image.equals("-") ? -1 : 1); - break; - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: - case MILITARY_ZONE: - z = obs_zone(); - break; - default: - jj_la1[5] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return z;} - throw new Error("Missing return statement in function"); - } - - final public int obs_zone() throws ParseException { - Token t; int z; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case 25: - jj_consume_token(25); - z=0; - break; - case 26: - jj_consume_token(26); - z=0; - break; - case 27: - jj_consume_token(27); - z=-5; - break; - case 28: - jj_consume_token(28); - z=-4; - break; - case 29: - jj_consume_token(29); - z=-6; - break; - case 30: - jj_consume_token(30); - z=-5; - break; - case 31: - jj_consume_token(31); - z=-7; - break; - case 32: - jj_consume_token(32); - z=-6; - break; - case 33: - jj_consume_token(33); - z=-8; - break; - case 34: - jj_consume_token(34); - z=-7; - break; - case MILITARY_ZONE: - t = jj_consume_token(MILITARY_ZONE); - z=getMilitaryZoneOffset(t.image.charAt(0)); - break; - default: - jj_la1[6] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return z * 100;} - throw new Error("Missing return statement in function"); - } - - public DateTimeParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private int jj_gen; - final private int[] jj_la1 = new int[7]; - static private int[] jj_la1_0; - static private int[] jj_la1_1; - static { - jj_la1_0(); - jj_la1_1(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0x2,0x7f0,0x7f0,0x7ff800,0x800000,0xff000000,0xfe000000,}; - } - private static void jj_la1_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0xf,0xf,}; - } - - public DateTimeParser(java.io.InputStream stream) { - this(stream, null); - } - public DateTimeParser(java.io.InputStream stream, String encoding) { - try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source = new DateTimeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - public void ReInit(java.io.InputStream stream, String encoding) { - try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public DateTimeParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new DateTimeParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public DateTimeParser(DateTimeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - public void ReInit(DateTimeParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 7; i++) jj_la1[i] = -1; - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private java.util.Vector jj_expentries = new java.util.Vector(); - private int[] jj_expentry; - private int jj_kind = -1; - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[49]; - for (int i = 0; i < 49; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 7; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1<", - "\"\\r\"", - "\"\\n\"", - "\",\"", - "\"Mon\"", - "\"Tue\"", - "\"Wed\"", - "\"Thu\"", - "\"Fri\"", - "\"Sat\"", - "\"Sun\"", - "\"Jan\"", - "\"Feb\"", - "\"Mar\"", - "\"Apr\"", - "\"May\"", - "\"Jun\"", - "\"Jul\"", - "\"Aug\"", - "\"Sep\"", - "\"Oct\"", - "\"Nov\"", - "\"Dec\"", - "\":\"", - "", - "\"UT\"", - "\"GMT\"", - "\"EST\"", - "\"EDT\"", - "\"CST\"", - "\"CDT\"", - "\"MST\"", - "\"MDT\"", - "\"PST\"", - "\"PDT\"", - "", - "", - "\"(\"", - "\")\"", - "", - "\"(\"", - "", - "", - "\"(\"", - "\")\"", - "", - "", - "", - "", - }; - -} diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java deleted file mode 100644 index e75998cf2..000000000 --- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java +++ /dev/null @@ -1,882 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. DateTimeParserTokenManager.java */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; -import org.apache.james.mime4j.field.datetime.DateTime; -import java.util.Calendar; - -public class DateTimeParserTokenManager implements DateTimeParserConstants -{ - // Keeps track of how many levels of comment nesting - // we've encountered. This is only used when the 2nd - // level is reached, for example ((this)), not (this). - // This is because the outermost level must be treated - // specially anyway, because the outermost ")" has a - // different token type than inner ")" instances. - static int commentNest; - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - case 0: - if ((active0 & 0x7fe7cf7f0L) != 0L) - { - jjmatchedKind = 35; - return -1; - } - return -1; - case 1: - if ((active0 & 0x7fe7cf7f0L) != 0L) - { - if (jjmatchedPos == 0) - { - jjmatchedKind = 35; - jjmatchedPos = 0; - } - return -1; - } - return -1; - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 10: - return jjStopAtPos(0, 2); - case 13: - return jjStopAtPos(0, 1); - case 40: - return jjStopAtPos(0, 37); - case 44: - return jjStopAtPos(0, 3); - case 58: - return jjStopAtPos(0, 23); - case 65: - return jjMoveStringLiteralDfa1_0(0x44000L); - case 67: - return jjMoveStringLiteralDfa1_0(0x60000000L); - case 68: - return jjMoveStringLiteralDfa1_0(0x400000L); - case 69: - return jjMoveStringLiteralDfa1_0(0x18000000L); - case 70: - return jjMoveStringLiteralDfa1_0(0x1100L); - case 71: - return jjMoveStringLiteralDfa1_0(0x4000000L); - case 74: - return jjMoveStringLiteralDfa1_0(0x30800L); - case 77: - return jjMoveStringLiteralDfa1_0(0x18000a010L); - case 78: - return jjMoveStringLiteralDfa1_0(0x200000L); - case 79: - return jjMoveStringLiteralDfa1_0(0x100000L); - case 80: - return jjMoveStringLiteralDfa1_0(0x600000000L); - case 83: - return jjMoveStringLiteralDfa1_0(0x80600L); - case 84: - return jjMoveStringLiteralDfa1_0(0xa0L); - case 85: - return jjMoveStringLiteralDfa1_0(0x2000000L); - case 87: - return jjMoveStringLiteralDfa1_0(0x40L); - default : - return jjMoveNfa_0(0, 0); - } -} -private final int jjMoveStringLiteralDfa1_0(long active0) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(0, active0); - return 1; - } - switch(curChar) - { - case 68: - return jjMoveStringLiteralDfa2_0(active0, 0x550000000L); - case 77: - return jjMoveStringLiteralDfa2_0(active0, 0x4000000L); - case 83: - return jjMoveStringLiteralDfa2_0(active0, 0x2a8000000L); - case 84: - if ((active0 & 0x2000000L) != 0L) - return jjStopAtPos(1, 25); - break; - case 97: - return jjMoveStringLiteralDfa2_0(active0, 0xaa00L); - case 99: - return jjMoveStringLiteralDfa2_0(active0, 0x100000L); - case 101: - return jjMoveStringLiteralDfa2_0(active0, 0x481040L); - case 104: - return jjMoveStringLiteralDfa2_0(active0, 0x80L); - case 111: - return jjMoveStringLiteralDfa2_0(active0, 0x200010L); - case 112: - return jjMoveStringLiteralDfa2_0(active0, 0x4000L); - case 114: - return jjMoveStringLiteralDfa2_0(active0, 0x100L); - case 117: - return jjMoveStringLiteralDfa2_0(active0, 0x70420L); - default : - break; - } - return jjStartNfa_0(0, active0); -} -private final int jjMoveStringLiteralDfa2_0(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_0(0, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(1, active0); - return 2; - } - switch(curChar) - { - case 84: - if ((active0 & 0x4000000L) != 0L) - return jjStopAtPos(2, 26); - else if ((active0 & 0x8000000L) != 0L) - return jjStopAtPos(2, 27); - else if ((active0 & 0x10000000L) != 0L) - return jjStopAtPos(2, 28); - else if ((active0 & 0x20000000L) != 0L) - return jjStopAtPos(2, 29); - else if ((active0 & 0x40000000L) != 0L) - return jjStopAtPos(2, 30); - else if ((active0 & 0x80000000L) != 0L) - return jjStopAtPos(2, 31); - else if ((active0 & 0x100000000L) != 0L) - return jjStopAtPos(2, 32); - else if ((active0 & 0x200000000L) != 0L) - return jjStopAtPos(2, 33); - else if ((active0 & 0x400000000L) != 0L) - return jjStopAtPos(2, 34); - break; - case 98: - if ((active0 & 0x1000L) != 0L) - return jjStopAtPos(2, 12); - break; - case 99: - if ((active0 & 0x400000L) != 0L) - return jjStopAtPos(2, 22); - break; - case 100: - if ((active0 & 0x40L) != 0L) - return jjStopAtPos(2, 6); - break; - case 101: - if ((active0 & 0x20L) != 0L) - return jjStopAtPos(2, 5); - break; - case 103: - if ((active0 & 0x40000L) != 0L) - return jjStopAtPos(2, 18); - break; - case 105: - if ((active0 & 0x100L) != 0L) - return jjStopAtPos(2, 8); - break; - case 108: - if ((active0 & 0x20000L) != 0L) - return jjStopAtPos(2, 17); - break; - case 110: - if ((active0 & 0x10L) != 0L) - return jjStopAtPos(2, 4); - else if ((active0 & 0x400L) != 0L) - return jjStopAtPos(2, 10); - else if ((active0 & 0x800L) != 0L) - return jjStopAtPos(2, 11); - else if ((active0 & 0x10000L) != 0L) - return jjStopAtPos(2, 16); - break; - case 112: - if ((active0 & 0x80000L) != 0L) - return jjStopAtPos(2, 19); - break; - case 114: - if ((active0 & 0x2000L) != 0L) - return jjStopAtPos(2, 13); - else if ((active0 & 0x4000L) != 0L) - return jjStopAtPos(2, 14); - break; - case 116: - if ((active0 & 0x200L) != 0L) - return jjStopAtPos(2, 9); - else if ((active0 & 0x100000L) != 0L) - return jjStopAtPos(2, 20); - break; - case 117: - if ((active0 & 0x80L) != 0L) - return jjStopAtPos(2, 7); - break; - case 118: - if ((active0 & 0x200000L) != 0L) - return jjStopAtPos(2, 21); - break; - case 121: - if ((active0 & 0x8000L) != 0L) - return jjStopAtPos(2, 15); - break; - default : - break; - } - return jjStartNfa_0(1, active0); -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 4; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 46) - kind = 46; - jjCheckNAdd(3); - } - else if ((0x100000200L & l) != 0L) - { - if (kind > 36) - kind = 36; - jjCheckNAdd(2); - } - else if ((0x280000000000L & l) != 0L) - { - if (kind > 24) - kind = 24; - } - break; - case 2: - if ((0x100000200L & l) == 0L) - break; - kind = 36; - jjCheckNAdd(2); - break; - case 3: - if ((0x3ff000000000000L & l) == 0L) - break; - kind = 46; - jjCheckNAdd(3); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x7fffbfe07fffbfeL & l) != 0L) - kind = 35; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_1(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_1(int pos, long active0) -{ - return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_1(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_1(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_1() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 40); - case 41: - return jjStopAtPos(0, 38); - default : - return jjMoveNfa_1(0, 0); - } -} -static final long[] jjbitVec0 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 41) - kind = 41; - break; - case 1: - if (kind > 39) - kind = 39; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 41) - kind = 41; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 39) - kind = 39; - break; - case 2: - if (kind > 41) - kind = 41; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 41) - kind = 41; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 39) - kind = 39; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_2(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_2(int pos, long active0) -{ - return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_2(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_2(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_2() -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 43); - case 41: - return jjStopAtPos(0, 44); - default : - return jjMoveNfa_2(0, 0); - } -} -private final int jjMoveNfa_2(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 45) - kind = 45; - break; - case 1: - if (kind > 42) - kind = 42; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (kind > 45) - kind = 45; - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (kind > 42) - kind = 42; - break; - case 2: - if (kind > 45) - kind = 45; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((jjbitVec0[i2] & l2) != 0L && kind > 45) - kind = 45; - break; - case 1: - if ((jjbitVec0[i2] & l2) != 0L && kind > 42) - kind = 42; - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { -}; -public static final String[] jjstrLiteralImages = { -"", "\15", "\12", "\54", "\115\157\156", "\124\165\145", "\127\145\144", -"\124\150\165", "\106\162\151", "\123\141\164", "\123\165\156", "\112\141\156", -"\106\145\142", "\115\141\162", "\101\160\162", "\115\141\171", "\112\165\156", -"\112\165\154", "\101\165\147", "\123\145\160", "\117\143\164", "\116\157\166", -"\104\145\143", "\72", null, "\125\124", "\107\115\124", "\105\123\124", "\105\104\124", -"\103\123\124", "\103\104\124", "\115\123\124", "\115\104\124", "\120\123\124", -"\120\104\124", null, null, null, null, null, null, null, null, null, null, null, null, null, -null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "INCOMMENT", - "NESTED_COMMENT", -}; -public static final int[] jjnewLexState = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -}; -static final long[] jjtoToken = { - 0x400fffffffffL, -}; -static final long[] jjtoSkip = { - 0x5000000000L, -}; -static final long[] jjtoSpecial = { - 0x1000000000L, -}; -static final long[] jjtoMore = { - 0x3fa000000000L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[4]; -private final int[] jjstateSet = new int[8]; -StringBuffer image; -int jjimageLen; -int lengthOfMatch; -protected char curChar; -public DateTimeParserTokenManager(SimpleCharStream stream){ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public DateTimeParserTokenManager(SimpleCharStream stream, int lexState){ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 4; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 3 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - return matchedToken; - } - image = null; - jjimageLen = 0; - - for (;;) - { - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - break; - case 1: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - break; - case 2: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_2(); - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (specialToken == null) - specialToken = matchedToken; - else - { - matchedToken.specialToken = specialToken; - specialToken = (specialToken.next = matchedToken); - } - } - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - MoreLexicalActions(); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - curPos = 0; - jjmatchedKind = 0x7fffffff; - try { - curChar = input_stream.readChar(); - continue; - } - catch (java.io.IOException e1) { } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } -} - -void MoreLexicalActions() -{ - jjimageLen += (lengthOfMatch = jjmatchedPos + 1); - switch(jjmatchedKind) - { - case 39 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 40 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - commentNest = 1; - break; - case 42 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - image.deleteCharAt(image.length() - 2); - break; - case 43 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - ++commentNest; - break; - case 44 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen)); - jjimageLen = 0; - --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); - break; - default : - break; - } -} -} diff --git a/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java b/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java deleted file mode 100644 index 418699107..000000000 --- a/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java +++ /dev/null @@ -1,207 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - StringBuffer expected = new StringBuffer(); - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} diff --git a/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java deleted file mode 100644 index d44a9018b..000000000 --- a/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java +++ /dev/null @@ -1,454 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} diff --git a/src/org/apache/james/mime4j/field/datetime/parser/Token.java b/src/org/apache/james/mime4j/field/datetime/parser/Token.java deleted file mode 100644 index 52d101ed0..000000000 --- a/src/org/apache/james/mime4j/field/datetime/parser/Token.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} diff --git a/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java deleted file mode 100644 index 973255070..000000000 --- a/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java +++ /dev/null @@ -1,148 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -/* - * Copyright 2004 the mime4j project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.james.mime4j.field.datetime.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} diff --git a/src/org/apache/james/mime4j/message/AbstractBody.java b/src/org/apache/james/mime4j/message/AbstractBody.java deleted file mode 100644 index d2647ec77..000000000 --- a/src/org/apache/james/mime4j/message/AbstractBody.java +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - - -/** - * Abstract Body implementation providing the parent - * functionality required by bodies. - * - * - * @version $Id: AbstractBody.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -public abstract class AbstractBody implements Body { - private Entity parent = null; - - /** - * @see org.apache.james.mime4j.message.Body#getParent() - */ - public Entity getParent() { - return parent; - } - - /** - * @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity) - */ - public void setParent(Entity parent) { - this.parent = parent; - } - -} diff --git a/src/org/apache/james/mime4j/message/BinaryBody.java b/src/org/apache/james/mime4j/message/BinaryBody.java deleted file mode 100644 index bfc992a8f..000000000 --- a/src/org/apache/james/mime4j/message/BinaryBody.java +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.InputStream; - - -/** - * Interface implemented by bodies containing binary data. - * - * - * @version $Id: BinaryBody.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $ - */ -public interface BinaryBody extends Body { - - /** - * Gets a InputStream which reads the bytes of the - * body. - * - * @return the stream. - * @throws IOException on I/O errors. - */ - InputStream getInputStream() throws IOException; -} diff --git a/src/org/apache/james/mime4j/message/Body.java b/src/org/apache/james/mime4j/message/Body.java deleted file mode 100644 index 54b8948db..000000000 --- a/src/org/apache/james/mime4j/message/Body.java +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Encapsulates the body of an entity (see RFC 2045). - * - * - * @version $Id: Body.java,v 1.4 2004/10/04 15:36:43 ntherning Exp $ - */ -public interface Body { - - /** - * Gets the parent of this body. - * - * @return the parent. - */ - Entity getParent(); - - /** - * Sets the parent of this body. - * - * @param parent the parent. - */ - void setParent(Entity parent); - - /** - * Writes this body to the given stream in MIME message format. - * - * @param out the stream to write to. - * @throws IOException on I/O errors. - */ - void writeTo(OutputStream out) throws IOException; -} diff --git a/src/org/apache/james/mime4j/message/BodyPart.java b/src/org/apache/james/mime4j/message/BodyPart.java deleted file mode 100644 index 474030d7f..000000000 --- a/src/org/apache/james/mime4j/message/BodyPart.java +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.OutputStream; - - -/** - * Represents a MIME body part (see RFC 2045). - * - * - * @version $Id: BodyPart.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $ - */ -public class BodyPart extends Entity { - - /** - * - * @see org.apache.james.mime4j.message.Entity#writeTo(java.io.OutputStream) - */ - public void writeTo(OutputStream out) throws IOException { - getHeader().writeTo(out); - getBody().writeTo(out); - } -} diff --git a/src/org/apache/james/mime4j/message/Entity.java b/src/org/apache/james/mime4j/message/Entity.java deleted file mode 100644 index 96f2a4875..000000000 --- a/src/org/apache/james/mime4j/message/Entity.java +++ /dev/null @@ -1,170 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.james.mime4j.field.ContentTransferEncodingField; -import org.apache.james.mime4j.field.ContentTypeField; -import org.apache.james.mime4j.field.Field; - -/** - * MIME entity. An entity has a header and a body (see RFC 2045). - * - * - * @version $Id: Entity.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $ - */ -public abstract class Entity { - private Header header = null; - private Body body = null; - private Entity parent = null; - - /** - * Gets the parent entity of this entity. - * Returns null if this is the root entity. - * - * @return the parent or null. - */ - public Entity getParent() { - return parent; - } - - /** - * Sets the parent entity of this entity. - * - * @param parent the parent entity or null if - * this will be the root entity. - */ - public void setParent(Entity parent) { - this.parent = parent; - } - - /** - * Gets the entity header. - * - * @return the header. - */ - public Header getHeader() { - return header; - } - - /** - * Sets the entity header. - * - * @param header the header. - */ - public void setHeader(Header header) { - this.header = header; - } - - /** - * Gets the body of this entity. - * - * @return the body, - */ - public Body getBody() { - return body; - } - - /** - * Sets the body of this entity. - * - * @param body the body. - */ - public void setBody(Body body) { - this.body = body; - body.setParent(this); - } - - /** - * Determines the MIME type of this Entity. The MIME type - * is derived by looking at the parent's Content-Type field if no - * Content-Type field is set for this Entity. - * - * @return the MIME type. - */ - public String getMimeType() { - ContentTypeField child = - (ContentTypeField) getHeader().getField(Field.CONTENT_TYPE); - ContentTypeField parent = getParent() != null - ? (ContentTypeField) getParent().getHeader(). - getField(Field.CONTENT_TYPE) - : null; - - return ContentTypeField.getMimeType(child, parent); - } - - /** - * Determines the MIME character set encoding of this Entity. - * - * @return the MIME character set encoding. - */ - public String getCharset() { - return ContentTypeField.getCharset( - (ContentTypeField) getHeader().getField(Field.CONTENT_TYPE)); - } - - /** - * Determines the transfer encoding of this Entity. - * - * @return the transfer encoding. - */ - public String getContentTransferEncoding() { - ContentTransferEncodingField f = (ContentTransferEncodingField) - getHeader().getField(Field.CONTENT_TRANSFER_ENCODING); - - return ContentTransferEncodingField.getEncoding(f); - } - - /** - * Determines if the MIME type of this Entity matches the - * given one. MIME types are case-insensitive. - * - * @param type the MIME type to match against. - * @return true on match, false otherwise. - */ - public boolean isMimeType(String type) { - return getMimeType().equalsIgnoreCase(type); - } - - /** - * Determines if the MIME type of this Entity is - * multipart/*. Since multipart-entities must have - * a boundary parameter in the Content-Type field this - * method returns false if no boundary exists. - * - * @return true on match, false otherwise. - */ - public boolean isMultipart() { - ContentTypeField f = - (ContentTypeField) getHeader().getField(Field.CONTENT_TYPE); - return f != null && f.getBoundary() != null - && getMimeType().startsWith(ContentTypeField.TYPE_MULTIPART_PREFIX); - } - - /** - * Write the content to the given outputstream - * - * @param out the outputstream to write to - * @throws IOException - */ - public abstract void writeTo(OutputStream out) throws IOException; -} diff --git a/src/org/apache/james/mime4j/message/Header.java b/src/org/apache/james/mime4j/message/Header.java deleted file mode 100644 index 90a0ef480..000000000 --- a/src/org/apache/james/mime4j/message/Header.java +++ /dev/null @@ -1,155 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import org.apache.james.mime4j.AbstractContentHandler; -import org.apache.james.mime4j.MimeStreamParser; -import org.apache.james.mime4j.field.ContentTypeField; -import org.apache.james.mime4j.field.Field; -import org.apache.james.mime4j.util.CharsetUtil; - - -/** - * The header of an entity (see RFC 2045). - * - * - * @version $Id: Header.java,v 1.3 2004/10/04 15:36:44 ntherning Exp $ - */ -public class Header { - private List fields = new LinkedList(); - private HashMap fieldMap = new HashMap(); - - /** - * Creates a new empty Header. - */ - public Header() { - } - - /** - * Creates a new Header from the specified stream. - * - * @param is the stream to read the header from. - */ - public Header(InputStream is) throws IOException { - final MimeStreamParser parser = new MimeStreamParser(); - parser.setContentHandler(new AbstractContentHandler() { - public void endHeader() { - parser.stop(); - } - public void field(String fieldData) { - addField(Field.parse(fieldData)); - } - }); - parser.parse(is); - } - - /** - * Adds a field to the end of the list of fields. - * - * @param field the field to add. - */ - public void addField(Field field) { - List values = (List) fieldMap.get(field.getName().toLowerCase()); - if (values == null) { - values = new LinkedList(); - fieldMap.put(field.getName().toLowerCase(), values); - } - values.add(field); - fields.add(field); - } - - /** - * Gets the fields of this header. The returned list will not be - * modifiable. - * - * @return the list of Field objects. - */ - public List getFields() { - return Collections.unmodifiableList(fields); - } - - /** - * Gets a Field given a field name. If there are multiple - * such fields defined in this header the first one will be returned. - * - * @param name the field name (e.g. From, Subject). - * @return the field or null if none found. - */ - public Field getField(String name) { - List l = (List) fieldMap.get(name.toLowerCase()); - if (l != null && !l.isEmpty()) { - return (Field) l.get(0); - } - return null; - } - - /** - * Gets all Fields having the specified field name. - * - * @param name the field name (e.g. From, Subject). - * @return the list of fields. - */ - public List getFields(String name) { - List l = (List) fieldMap.get(name.toLowerCase()); - return Collections.unmodifiableList(l); - } - - /** - * Return Header Object as String representation. Each headerline is - * seperated by "\r\n" - * - * @return headers - */ - public String toString() { - StringBuffer str = new StringBuffer(); - for (Iterator it = fields.iterator(); it.hasNext();) { - str.append(it.next().toString()); - str.append("\r\n"); - } - return str.toString(); - } - - - /** - * Write the Header to the given OutputStream - * - * @param out the OutputStream to write to - * @throws IOException - */ - public void writeTo(OutputStream out) throws IOException { - String charString = ((ContentTypeField) getField(Field.CONTENT_TYPE)).getCharset(); - - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, CharsetUtil.getCharset(charString)),8192); - writer.write(toString()+ "\r\n"); - writer.flush(); - } - -} diff --git a/src/org/apache/james/mime4j/message/MemoryBinaryBody.java b/src/org/apache/james/mime4j/message/MemoryBinaryBody.java deleted file mode 100644 index 0db44e199..000000000 --- a/src/org/apache/james/mime4j/message/MemoryBinaryBody.java +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.util.TempPath; -import org.apache.james.mime4j.util.TempStorage; - - -/** - * Binary body backed by a {@link org.apache.james.mime4j.util.TempFile}. - * - * - * @version $Id: TempFileBinaryBody.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -class MemoryBinaryBody extends AbstractBody implements BinaryBody { - private static Log log = LogFactory.getLog(MemoryBinaryBody.class); - - private Entity parent = null; - private byte[] tempFile = null; - - /** - * Use the given InputStream to build the TemporyFileBinaryBody - * - * @param is the InputStream to use as source - * @throws IOException - */ - public MemoryBinaryBody(InputStream is) throws IOException { - - TempPath tempPath = TempStorage.getInstance().getRootTempPath(); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - IOUtils.copy(is, out); - out.close(); - tempFile = out.toByteArray(); - } - - /** - * @see org.apache.james.mime4j.message.AbstractBody#getParent() - */ - public Entity getParent() { - return parent; - } - - /** - * @see org.apache.james.mime4j.message.AbstractBody#setParent(org.apache.james.mime4j.message.Entity) - */ - public void setParent(Entity parent) { - this.parent = parent; - } - - /** - * @see org.apache.james.mime4j.message.BinaryBody#getInputStream() - */ - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(tempFile); - } - - /** - * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream) - */ - public void writeTo(OutputStream out) throws IOException { - IOUtils.copy(getInputStream(),out); - } -} diff --git a/src/org/apache/james/mime4j/message/MemoryTextBody.java b/src/org/apache/james/mime4j/message/MemoryTextBody.java deleted file mode 100644 index e5e9d9d72..000000000 --- a/src/org/apache/james/mime4j/message/MemoryTextBody.java +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.UnsupportedEncodingException; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.util.CharsetUtil; -import org.apache.james.mime4j.util.TempPath; -import org.apache.james.mime4j.util.TempStorage; - - -/** - * Text body backed by a {@link org.apache.james.mime4j.util.TempFile}. - * - * - * @version $Id: TempFileTextBody.java,v 1.3 2004/10/25 07:26:46 ntherning Exp $ - */ -class MemoryTextBody extends AbstractBody implements TextBody { - private static Log log = LogFactory.getLog(MemoryTextBody.class); - - private String mimeCharset = null; - private byte[] tempFile = null; - - public MemoryTextBody(InputStream is) throws IOException { - this(is, null); - } - - public MemoryTextBody(InputStream is, String mimeCharset) - throws IOException { - - this.mimeCharset = mimeCharset; - - TempPath tempPath = TempStorage.getInstance().getRootTempPath(); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - IOUtils.copy(is, out); - out.close(); - tempFile = out.toByteArray(); - } - - /** - * @see org.apache.james.mime4j.message.TextBody#getReader() - */ - public Reader getReader() throws UnsupportedEncodingException, IOException { - String javaCharset = null; - if (mimeCharset != null) { - javaCharset = CharsetUtil.toJavaCharset(mimeCharset); - } - - if (javaCharset == null) { - javaCharset = "ISO-8859-1"; - - if (log.isWarnEnabled()) { - if (mimeCharset == null) { - log.warn("No MIME charset specified. Using " + javaCharset - + " instead."); - } else { - log.warn("MIME charset '" + mimeCharset + "' has no " - + "corresponding Java charset. Using " + javaCharset - + " instead."); - } - } - } - /* - if (log.isWarnEnabled()) { - if (mimeCharset == null) { - log.warn("No MIME charset specified. Using the " - + "platform's default charset."); - } else { - log.warn("MIME charset '" + mimeCharset + "' has no " - + "corresponding Java charset. Using the " - + "platform's default charset."); - } - } - - return new InputStreamReader(tempFile.getInputStream()); - }*/ - - return new InputStreamReader(new ByteArrayInputStream(tempFile), javaCharset); - } - - - /** - * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream) - */ - public void writeTo(OutputStream out) throws IOException { - IOUtils.copy(new ByteArrayInputStream(tempFile), out); - } -} diff --git a/src/org/apache/james/mime4j/message/Message.java b/src/org/apache/james/mime4j/message/Message.java deleted file mode 100644 index fc28c586a..000000000 --- a/src/org/apache/james/mime4j/message/Message.java +++ /dev/null @@ -1,256 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Stack; - -import org.apache.james.mime4j.BodyDescriptor; -import org.apache.james.mime4j.ContentHandler; -import org.apache.james.mime4j.MimeStreamParser; -import org.apache.james.mime4j.decoder.Base64InputStream; -import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; -import org.apache.james.mime4j.field.Field; -import org.apache.james.mime4j.field.UnstructuredField; - - -/** - * Represents a MIME message. The following code parses a stream into a - * Message object. - * - *
- *      Message msg = new Message(new BufferedInputStream(
- *                                      new FileInputStream("mime.msg")));
- * 
- * - * - * - * @version $Id: Message.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $ - */ -public class Message extends Entity implements Body { - - /** - * Creates a new empty Message. - */ - public Message() { - } - - /** - * Parses the specified MIME message stream into a Message - * instance. - * - * @param is the stream to parse. - * @throws IOException on I/O errors. - */ - public Message(InputStream is) throws IOException { - MimeStreamParser parser = new MimeStreamParser(); - parser.setContentHandler(new MessageBuilder()); - parser.parse(is); - } - - - /** - * Gets the Subject field. - * - * @return the Subject field or null if it - * doesn't exist. - */ - public UnstructuredField getSubject() { - return (UnstructuredField) getHeader().getField(Field.SUBJECT); - } - - /** - * - * @see org.apache.james.mime4j.message.Entity#writeTo(java.io.OutputStream) - */ - public void writeTo(OutputStream out) throws IOException { - getHeader().writeTo(out); - - Body body = getBody(); - if (body instanceof Multipart) { - Multipart mp = (Multipart) body; - mp.writeTo(out); - } else { - body.writeTo(out); - } - } - - - private class MessageBuilder implements ContentHandler { - private Stack stack = new Stack(); - - public MessageBuilder() { - } - - private void expect(Class c) { - if (!c.isInstance(stack.peek())) { - throw new IllegalStateException("Internal stack error: " - + "Expected '" + c.getName() + "' found '" - + stack.peek().getClass().getName() + "'"); - } - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startMessage() - */ - public void startMessage() { - if (stack.isEmpty()) { - stack.push(Message.this); - } else { - expect(Entity.class); - Message m = new Message(); - ((Entity) stack.peek()).setBody(m); - stack.push(m); - } - } - - /** - * @see org.apache.james.mime4j.ContentHandler#endMessage() - */ - public void endMessage() { - expect(Message.class); - stack.pop(); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startHeader() - */ - public void startHeader() { - stack.push(new Header()); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#field(java.lang.String) - */ - public void field(String fieldData) { - expect(Header.class); - ((Header) stack.peek()).addField(Field.parse(fieldData)); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#endHeader() - */ - public void endHeader() { - expect(Header.class); - Header h = (Header) stack.pop(); - expect(Entity.class); - ((Entity) stack.peek()).setHeader(h); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startMultipart(org.apache.james.mime4j.BodyDescriptor) - */ - public void startMultipart(BodyDescriptor bd) { - expect(Entity.class); - - Entity e = (Entity) stack.peek(); - Multipart multiPart = new Multipart(); - e.setBody(multiPart); - stack.push(multiPart); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream) - */ - public void body(BodyDescriptor bd, InputStream is) throws IOException { - expect(Entity.class); - - String enc = bd.getTransferEncoding(); - if ("base64".equals(enc)) { - is = new Base64InputStream(is); - } else if ("quoted-printable".equals(enc)) { - is = new QuotedPrintableInputStream(is); - } - - Body body = null; - if (bd.getMimeType().startsWith("text/")) { - body = new MemoryTextBody(is, bd.getCharset()); - } else { - body = new MemoryBinaryBody(is); - } - - ((Entity) stack.peek()).setBody(body); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#endMultipart() - */ - public void endMultipart() { - stack.pop(); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#startBodyPart() - */ - public void startBodyPart() { - expect(Multipart.class); - - BodyPart bodyPart = new BodyPart(); - ((Multipart) stack.peek()).addBodyPart(bodyPart); - stack.push(bodyPart); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#endBodyPart() - */ - public void endBodyPart() { - expect(BodyPart.class); - stack.pop(); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#epilogue(java.io.InputStream) - */ - public void epilogue(InputStream is) throws IOException { - expect(Multipart.class); - StringBuffer sb = new StringBuffer(); - int b; - while ((b = is.read()) != -1) { - sb.append((char) b); - } - ((Multipart) stack.peek()).setEpilogue(sb.toString()); - } - - /** - * @see org.apache.james.mime4j.ContentHandler#preamble(java.io.InputStream) - */ - public void preamble(InputStream is) throws IOException { - expect(Multipart.class); - StringBuffer sb = new StringBuffer(); - int b; - while ((b = is.read()) != -1) { - sb.append((char) b); - } - ((Multipart) stack.peek()).setPreamble(sb.toString()); - } - - /** - * TODO: Implement me - * - * @see org.apache.james.mime4j.ContentHandler#raw(java.io.InputStream) - */ - public void raw(InputStream is) throws IOException { - throw new UnsupportedOperationException("Not supported"); - } - - } -} diff --git a/src/org/apache/james/mime4j/message/Multipart.java b/src/org/apache/james/mime4j/message/Multipart.java deleted file mode 100644 index 3c4b519c4..000000000 --- a/src/org/apache/james/mime4j/message/Multipart.java +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import org.apache.james.mime4j.field.ContentTypeField; -import org.apache.james.mime4j.field.Field; -import org.apache.james.mime4j.util.CharsetUtil; - -/** - * Represents a MIME multipart body (see RFC 2045).A multipart body has a - * ordered list of body parts. The multipart body also has a preamble and - * epilogue. The preamble consists of whatever characters appear before the - * first body part while the epilogue consists of whatever characters come - * after the last body part. - * - * - * @version $Id: Multipart.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $ - */ -public class Multipart implements Body { - private String preamble = ""; - private String epilogue = ""; - private List bodyParts = new LinkedList(); - private Entity parent = null; - private String subType = "alternative"; - - /** - * Creates a new empty Multipart instance. - */ - public Multipart() { - } - - /** - * Gets the multipart sub-type. E.g. alternative (the default) - * or parallel. See RFC 2045 for common sub-types and their - * meaning. - * - * @return the multipart sub-type. - */ - public String getSubType() { - return subType; - } - - /** - * Sets the multipart sub-type. E.g. alternative - * or parallel. See RFC 2045 for common sub-types and their - * meaning. - * - * @param subType the sub-type. - */ - public void setSubType(String subType) { - this.subType = subType; - } - - /** - * @see org.apache.james.mime4j.message.Body#getParent() - */ - public Entity getParent() { - return parent; - } - - /** - * @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity) - */ - public void setParent(Entity parent) { - this.parent = parent; - for (Iterator it = bodyParts.iterator(); it.hasNext();) { - ((BodyPart) it.next()).setParent(parent); - } - } - - /** - * Gets the epilogue. - * - * @return the epilogue. - */ - public String getEpilogue() { - return epilogue; - } - - /** - * Sets the epilogue. - * - * @param epilogue the epilogue. - */ - public void setEpilogue(String epilogue) { - this.epilogue = epilogue; - } - - /** - * Gets the list of body parts. The list is immutable. - * - * @return the list of BodyPart objects. - */ - public List getBodyParts() { - return Collections.unmodifiableList(bodyParts); - } - - /** - * Sets the list of body parts. - * - * @param bodyParts the new list of BodyPart objects. - */ - public void setBodyParts(List bodyParts) { - this.bodyParts = bodyParts; - for (Iterator it = bodyParts.iterator(); it.hasNext();) { - ((BodyPart) it.next()).setParent(parent); - } - } - - /** - * Adds a body part to the end of the list of body parts. - * - * @param bodyPart the body part. - */ - public void addBodyPart(BodyPart bodyPart) { - bodyParts.add(bodyPart); - bodyPart.setParent(parent); - } - - /** - * Gets the preamble. - * - * @return the preamble. - */ - public String getPreamble() { - return preamble; - } - - /** - * Sets the preamble. - * - * @param preamble the preamble. - */ - public void setPreamble(String preamble) { - this.preamble = preamble; - } - - /** - * - * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream) - */ - public void writeTo(OutputStream out) throws IOException { - String boundary = getBoundary(); - List bodyParts = getBodyParts(); - - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, CharsetUtil.getCharset(getCharset())),8192); - - writer.write(getPreamble() + "\r\n"); - - for (int i = 0; i < bodyParts.size(); i++) { - writer.write(boundary + "\r\n"); - ((BodyPart) bodyParts.get(i)).writeTo(out); - } - - writer.write(getEpilogue() + "\r\n"); - writer.write(boundary + "--" + "\r\n"); - - } - - /** - * Return the boundory of the parent Entity - * - * @return boundery - */ - private String getBoundary() { - Entity e = getParent(); - ContentTypeField cField = (ContentTypeField) e.getHeader().getField( - Field.CONTENT_TYPE); - return cField.getBoundary(); - } - - private String getCharset() { - Entity e = getParent(); - String charString = ((ContentTypeField) e.getHeader().getField(Field.CONTENT_TYPE)).getCharset(); - return charString; - } -} diff --git a/src/org/apache/james/mime4j/message/TempFileBinaryBody.java b/src/org/apache/james/mime4j/message/TempFileBinaryBody.java deleted file mode 100644 index 3ded83db8..000000000 --- a/src/org/apache/james/mime4j/message/TempFileBinaryBody.java +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.util.TempFile; -import org.apache.james.mime4j.util.TempPath; -import org.apache.james.mime4j.util.TempStorage; - - -/** - * Binary body backed by a {@link org.apache.james.mime4j.util.TempFile}. - * - * - * @version $Id: TempFileBinaryBody.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -class TempFileBinaryBody extends AbstractBody implements BinaryBody { - private static Log log = LogFactory.getLog(TempFileBinaryBody.class); - - private Entity parent = null; - private TempFile tempFile = null; - - /** - * Use the given InputStream to build the TemporyFileBinaryBody - * - * @param is the InputStream to use as source - * @throws IOException - */ - public TempFileBinaryBody(InputStream is) throws IOException { - - TempPath tempPath = TempStorage.getInstance().getRootTempPath(); - tempFile = tempPath.createTempFile("attachment", ".bin"); - - OutputStream out = tempFile.getOutputStream(); - IOUtils.copy(is, out); - out.close(); - } - - /** - * @see org.apache.james.mime4j.message.AbstractBody#getParent() - */ - public Entity getParent() { - return parent; - } - - /** - * @see org.apache.james.mime4j.message.AbstractBody#setParent(org.apache.james.mime4j.message.Entity) - */ - public void setParent(Entity parent) { - this.parent = parent; - } - - /** - * @see org.apache.james.mime4j.message.BinaryBody#getInputStream() - */ - public InputStream getInputStream() throws IOException { - return tempFile.getInputStream(); - } - - /** - * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream) - */ - public void writeTo(OutputStream out) throws IOException { - IOUtils.copy(getInputStream(),out); - } -} diff --git a/src/org/apache/james/mime4j/message/TempFileTextBody.java b/src/org/apache/james/mime4j/message/TempFileTextBody.java deleted file mode 100644 index 0b3b70c25..000000000 --- a/src/org/apache/james/mime4j/message/TempFileTextBody.java +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.UnsupportedEncodingException; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.james.mime4j.util.CharsetUtil; -import org.apache.james.mime4j.util.TempFile; -import org.apache.james.mime4j.util.TempPath; -import org.apache.james.mime4j.util.TempStorage; - - -/** - * Text body backed by a {@link org.apache.james.mime4j.util.TempFile}. - * - * - * @version $Id: TempFileTextBody.java,v 1.3 2004/10/25 07:26:46 ntherning Exp $ - */ -class TempFileTextBody extends AbstractBody implements TextBody { - private static Log log = LogFactory.getLog(TempFileTextBody.class); - - private String mimeCharset = null; - private TempFile tempFile = null; - - public TempFileTextBody(InputStream is) throws IOException { - this(is, null); - } - - public TempFileTextBody(InputStream is, String mimeCharset) - throws IOException { - - this.mimeCharset = mimeCharset; - - TempPath tempPath = TempStorage.getInstance().getRootTempPath(); - tempFile = tempPath.createTempFile("attachment", ".txt"); - - OutputStream out = tempFile.getOutputStream(); - IOUtils.copy(is, out); - out.close(); - } - - /** - * @see org.apache.james.mime4j.message.TextBody#getReader() - */ - public Reader getReader() throws UnsupportedEncodingException, IOException { - String javaCharset = null; - if (mimeCharset != null) { - javaCharset = CharsetUtil.toJavaCharset(mimeCharset); - } - - if (javaCharset == null) { - javaCharset = "ISO-8859-1"; - - if (log.isWarnEnabled()) { - if (mimeCharset == null) { - log.warn("No MIME charset specified. Using " + javaCharset - + " instead."); - } else { - log.warn("MIME charset '" + mimeCharset + "' has no " - + "corresponding Java charset. Using " + javaCharset - + " instead."); - } - } - } - /* - if (log.isWarnEnabled()) { - if (mimeCharset == null) { - log.warn("No MIME charset specified. Using the " - + "platform's default charset."); - } else { - log.warn("MIME charset '" + mimeCharset + "' has no " - + "corresponding Java charset. Using the " - + "platform's default charset."); - } - } - - return new InputStreamReader(tempFile.getInputStream()); - }*/ - - return new InputStreamReader(tempFile.getInputStream(), javaCharset); - } - - - /** - * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream) - */ - public void writeTo(OutputStream out) throws IOException { - IOUtils.copy(tempFile.getInputStream(), out); - } -} diff --git a/src/org/apache/james/mime4j/message/TextBody.java b/src/org/apache/james/mime4j/message/TextBody.java deleted file mode 100644 index 4fe714466..000000000 --- a/src/org/apache/james/mime4j/message/TextBody.java +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.message; - -import java.io.IOException; -import java.io.Reader; - - -/** - * Encapsulates the contents of a text/* entity body. - * - * - * @version $Id: TextBody.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $ - */ -public interface TextBody extends Body { - - /** - * Gets a Reader which may be used to read out the contents - * of this body. - * - * @return the Reader. - * @throws IOException on I/O errors. - */ - Reader getReader() throws IOException; -} diff --git a/src/org/apache/james/mime4j/util/CharsetUtil.java b/src/org/apache/james/mime4j/util/CharsetUtil.java deleted file mode 100644 index f5026b1f8..000000000 --- a/src/org/apache/james/mime4j/util/CharsetUtil.java +++ /dev/null @@ -1,1178 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.util; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; -import java.util.HashMap; -import java.util.TreeSet; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Utility class for working with character sets. It is somewhat similar to - * the Java 1.4 java.nio.charset.Charset class but knows many - * more aliases and is compatible with Java 1.3. It will use a simple detection - * mechanism to detect what character sets the current VM supports. This will - * be a sub-set of the character sets listed in the - * - * Java 1.5 (J2SE5.0) Supported Encodings document. - *

- * The - * IANA Character Sets document has been used to determine the preferred - * MIME character set names and to get a list of known aliases. - *

- * This is a complete list of the character sets known to this class: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Canonical (Java) nameMIME preferredAliases
ASCIIUS-ASCIIANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ISO646-US us IBM367 cp367 csASCII ascii7 646 iso_646.irv:1983
Big5Big5csBig5 CN-Big5 BIG-FIVE BIGFIVE
Big5_HKSCSBig5-HKSCSbig5hkscs
Big5_Solaris?
Cp037IBM037ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl csIBM037
Cp1006?
Cp1025?
Cp1026IBM1026csIBM1026
Cp1046?
Cp1047IBM1047IBM-1047
Cp1097?
Cp1098?
Cp1112?
Cp1122?
Cp1123?
Cp1124?
Cp1140IBM01140CCSID01140 CP01140 ebcdic-us-37+euro
Cp1141IBM01141CCSID01141 CP01141 ebcdic-de-273+euro
Cp1142IBM01142CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro
Cp1143IBM01143CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro
Cp1144IBM01144CCSID01144 CP01144 ebcdic-it-280+euro
Cp1145IBM01145CCSID01145 CP01145 ebcdic-es-284+euro
Cp1146IBM01146CCSID01146 CP01146 ebcdic-gb-285+euro
Cp1147IBM01147CCSID01147 CP01147 ebcdic-fr-297+euro
Cp1148IBM01148CCSID01148 CP01148 ebcdic-international-500+euro
Cp1149IBM01149CCSID01149 CP01149 ebcdic-is-871+euro
Cp1250windows-1250
Cp1251windows-1251
Cp1252windows-1252
Cp1253windows-1253
Cp1254windows-1254
Cp1255windows-1255
Cp1256windows-1256
Cp1257windows-1257
Cp1258windows-1258
Cp1381?
Cp1383?
Cp273IBM273csIBM273
Cp277IBM277EBCDIC-CP-DK EBCDIC-CP-NO csIBM277
Cp278IBM278CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278
Cp280IBM280ebcdic-cp-it csIBM280
Cp284IBM284ebcdic-cp-es csIBM284
Cp285IBM285ebcdic-cp-gb csIBM285
Cp297IBM297ebcdic-cp-fr csIBM297
Cp33722?
Cp420IBM420ebcdic-cp-ar1 csIBM420
Cp424IBM424ebcdic-cp-he csIBM424
Cp437IBM437437 csPC8CodePage437
Cp500IBM500ebcdic-cp-be ebcdic-cp-ch csIBM500
Cp737?
Cp775IBM775csPC775Baltic
Cp838IBM-Thai
Cp850IBM850850 csPC850Multilingual
Cp852IBM852852 csPCp852
Cp855IBM855855 csIBM855
Cp856?
Cp857IBM857857 csIBM857
Cp858IBM00858CCSID00858 CP00858 PC-Multilingual-850+euro
Cp860IBM860860 csIBM860
Cp861IBM861861 cp-is csIBM861
Cp862IBM862862 csPC862LatinHebrew
Cp863IBM863863 csIBM863
Cp864IBM864cp864 csIBM864
Cp865IBM865865 csIBM865
Cp866IBM866866 csIBM866
Cp868IBM868cp-ar csIBM868
Cp869IBM869cp-gr csIBM869
Cp870IBM870ebcdic-cp-roece ebcdic-cp-yu csIBM870
Cp871IBM871ebcdic-cp-is csIBM871
Cp875?
Cp918IBM918ebcdic-cp-ar2 csIBM918
Cp921?
Cp922?
Cp930?
Cp933?
Cp935?
Cp937?
Cp939?
Cp942?
Cp942C?
Cp943?
Cp943C?
Cp948?
Cp949?
Cp949C?
Cp950?
Cp964?
Cp970?
EUC_CNGB2312x-EUC-CN csGB2312 euccn euc-cn gb2312-80 gb2312-1980 CN-GB CN-GB-ISOIR165
EUC_JPEUC-JPcsEUCPkdFmtJapanese Extended_UNIX_Code_Packed_Format_for_Japanese eucjis x-eucjp eucjp x-euc-jp
EUC_JP_LINUX?
EUC_JP_Solaris?
EUC_KREUC-KRcsEUCKR ksc5601 5601 ksc5601_1987 ksc_5601 ksc5601-1987 ks_c_5601-1987 euckr
EUC_TWEUC-TWx-EUC-TW cns11643 euctw
GB18030GB18030gb18030-2000
GBKwindows-936CP936 MS936 ms_936 x-mswin-936
ISCII91?x-ISCII91 iscii
ISO2022CNISO-2022-CN
ISO2022JPISO-2022-JPcsISO2022JP JIS jis_encoding csjisencoding
ISO2022KRISO-2022-KRcsISO2022KR
ISO2022_CN_CNS?
ISO2022_CN_GB?
ISO8859_1ISO-8859-1ISO_8859-1:1987 iso-ir-100 ISO_8859-1 latin1 l1 IBM819 CP819 csISOLatin1 8859_1 819 IBM-819 ISO8859-1 ISO_8859_1
ISO8859_13ISO-8859-13
ISO8859_15ISO-8859-15ISO_8859-15 Latin-9 8859_15 csISOlatin9 IBM923 cp923 923 L9 IBM-923 ISO8859-15 LATIN9 LATIN0 csISOlatin0 ISO8859_15_FDIS
ISO8859_2ISO-8859-2ISO_8859-2:1987 iso-ir-101 ISO_8859-2 latin2 l2 csISOLatin2 8859_2 iso8859_2
ISO8859_3ISO-8859-3ISO_8859-3:1988 iso-ir-109 ISO_8859-3 latin3 l3 csISOLatin3 8859_3
ISO8859_4ISO-8859-4ISO_8859-4:1988 iso-ir-110 ISO_8859-4 latin4 l4 csISOLatin4 8859_4
ISO8859_5ISO-8859-5ISO_8859-5:1988 iso-ir-144 ISO_8859-5 cyrillic csISOLatinCyrillic 8859_5
ISO8859_6ISO-8859-6ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ECMA-114 ASMO-708 arabic csISOLatinArabic 8859_6
ISO8859_7ISO-8859-7ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ELOT_928 ECMA-118 greek greek8 csISOLatinGreek 8859_7 sun_eu_greek
ISO8859_8ISO-8859-8ISO_8859-8:1988 iso-ir-138 ISO_8859-8 hebrew csISOLatinHebrew 8859_8
ISO8859_9ISO-8859-9ISO_8859-9:1989 iso-ir-148 ISO_8859-9 latin5 l5 csISOLatin5 8859_9
JISAutoDetect?
JIS_C6626-1983JIS_C6626-1983x-JIS0208 JIS0208 csISO87JISX0208 x0208 JIS_X0208-1983 iso-ir-87
JIS_X0201JIS_X0201X0201 JIS0201 csHalfWidthKatakana
JIS_X0212-1990JIS_X0212-1990iso-ir-159 x0212 JIS0212 csISO159JISX02121990
KOI8_RKOI8-RcsKOI8R koi8
MS874windows-874cp874
MS932Windows-31Jwindows-932 csWindows31J x-ms-cp932
MS949windows-949windows949 ms_949 x-windows-949
MS950windows-950x-windows-950
MS950_HKSCS
MacArabic?
MacCentralEurope?
MacCroatian?
MacCyrillic?
MacDingbat?
MacGreekMacGreek
MacHebrew?
MacIceland?
MacRomanMacRomanMacintosh MAC csMacintosh
MacRomania?
MacSymbol?
MacThai?
MacTurkish?
MacUkraine?
SJISShift_JISMS_Kanji csShiftJIS shift-jis x-sjis pck
TIS620TIS-620
UTF-16UTF-16UTF_16
UTF8UTF-8
UnicodeBig?
UnicodeBigUnmarkedUTF-16BEX-UTF-16BE UTF_16BE ISO-10646-UCS-2
UnicodeLittle?
UnicodeLittleUnmarkedUTF-16LEUTF_16LE X-UTF-16LE
x-Johabjohabjohab cp1361 ms1361 ksc5601-1992 ksc5601_1992
x-iso-8859-11?
- * - * - * @version $Id: CharsetUtil.java,v 1.1 2004/10/25 07:26:46 ntherning Exp $ - */ -public class CharsetUtil { - private static Log log = LogFactory.getLog(CharsetUtil.class); - - private static class Charset implements Comparable { - private String canonical = null; - private String mime = null; - private String[] aliases = null; - - private Charset(String canonical, String mime, String[] aliases) { - this.canonical = canonical; - this.mime = mime; - this.aliases = aliases; - } - - public int compareTo(Object o) { - Charset c = (Charset) o; - return this.canonical.compareTo(c.canonical); - } - } - - private static Charset[] JAVA_CHARSETS = { - new Charset("ISO8859_1", "ISO-8859-1", - new String[] {"ISO_8859-1:1987", "iso-ir-100", "ISO_8859-1", - "latin1", "l1", "IBM819", "CP819", - "csISOLatin1", "8859_1", "819", "IBM-819", - "ISO8859-1", "ISO_8859_1"}), - new Charset("ISO8859_2", "ISO-8859-2", - new String[] {"ISO_8859-2:1987", "iso-ir-101", "ISO_8859-2", - "latin2", "l2", "csISOLatin2", "8859_2", - "iso8859_2"}), - new Charset("ISO8859_3", "ISO-8859-3", new String[] {"ISO_8859-3:1988", "iso-ir-109", "ISO_8859-3", "latin3", "l3", "csISOLatin3", "8859_3"}), - new Charset("ISO8859_4", "ISO-8859-4", - new String[] {"ISO_8859-4:1988", "iso-ir-110", "ISO_8859-4", - "latin4", "l4", "csISOLatin4", "8859_4"}), - new Charset("ISO8859_5", "ISO-8859-5", - new String[] {"ISO_8859-5:1988", "iso-ir-144", "ISO_8859-5", - "cyrillic", "csISOLatinCyrillic", "8859_5"}), - new Charset("ISO8859_6", "ISO-8859-6", new String[] {"ISO_8859-6:1987", "iso-ir-127", "ISO_8859-6", "ECMA-114", "ASMO-708", "arabic", "csISOLatinArabic", "8859_6"}), - new Charset("ISO8859_7", "ISO-8859-7", - new String[] {"ISO_8859-7:1987", "iso-ir-126", "ISO_8859-7", - "ELOT_928", "ECMA-118", "greek", "greek8", - "csISOLatinGreek", "8859_7", "sun_eu_greek"}), - new Charset("ISO8859_8", "ISO-8859-8", new String[] {"ISO_8859-8:1988", "iso-ir-138", "ISO_8859-8", "hebrew", "csISOLatinHebrew", "8859_8"}), - new Charset("ISO8859_9", "ISO-8859-9", - new String[] {"ISO_8859-9:1989", "iso-ir-148", "ISO_8859-9", - "latin5", "l5", "csISOLatin5", "8859_9"}), - - new Charset("ISO8859_13", "ISO-8859-13", new String[] {}), - new Charset("ISO8859_15", "ISO-8859-15", - new String[] {"ISO_8859-15", "Latin-9", "8859_15", - "csISOlatin9", "IBM923", "cp923", "923", "L9", - "IBM-923", "ISO8859-15", "LATIN9", "LATIN0", - "csISOlatin0", "ISO8859_15_FDIS"}), - new Charset("KOI8_R", "KOI8-R", new String[] {"csKOI8R", "koi8"}), - new Charset("ASCII", "US-ASCII", - new String[] {"ANSI_X3.4-1968", "iso-ir-6", - "ANSI_X3.4-1986", "ISO_646.irv:1991", - "ISO646-US", "us", "IBM367", "cp367", - "csASCII", "ascii7", "646", "iso_646.irv:1983"}), - new Charset("UTF8", "UTF-8", new String[] {}), - new Charset("UTF-16", "UTF-16", new String[] {"UTF_16"}), - new Charset("UnicodeBigUnmarked", "UTF-16BE", new String[] {"X-UTF-16BE", "UTF_16BE", "ISO-10646-UCS-2"}), - new Charset("UnicodeLittleUnmarked", "UTF-16LE", new String[] {"UTF_16LE", "X-UTF-16LE"}), - new Charset("Big5", "Big5", new String[] {"csBig5", "CN-Big5", "BIG-FIVE", "BIGFIVE"}), - new Charset("Big5_HKSCS", "Big5-HKSCS", new String[] {"big5hkscs"}), - new Charset("EUC_JP", "EUC-JP", - new String[] {"csEUCPkdFmtJapanese", - "Extended_UNIX_Code_Packed_Format_for_Japanese", - "eucjis", "x-eucjp", "eucjp", "x-euc-jp"}), - new Charset("EUC_KR", "EUC-KR", - new String[] {"csEUCKR", "ksc5601", "5601", "ksc5601_1987", - "ksc_5601", "ksc5601-1987", "ks_c_5601-1987", - "euckr"}), - new Charset("GB18030", "GB18030", new String[] {"gb18030-2000"}), - new Charset("EUC_CN", "GB2312", new String[] {"x-EUC-CN", "csGB2312", "euccn", "euc-cn", "gb2312-80", "gb2312-1980", "CN-GB", "CN-GB-ISOIR165"}), - new Charset("GBK", "windows-936", new String[] {"CP936", "MS936", "ms_936", "x-mswin-936"}), - - new Charset("Cp037", "IBM037", new String[] {"ebcdic-cp-us", "ebcdic-cp-ca", "ebcdic-cp-wt", "ebcdic-cp-nl", "csIBM037"}), - new Charset("Cp273", "IBM273", new String[] {"csIBM273"}), - new Charset("Cp277", "IBM277", new String[] {"EBCDIC-CP-DK", "EBCDIC-CP-NO", "csIBM277"}), - new Charset("Cp278", "IBM278", new String[] {"CP278", "ebcdic-cp-fi", "ebcdic-cp-se", "csIBM278"}), - new Charset("Cp280", "IBM280", new String[] {"ebcdic-cp-it", "csIBM280"}), - new Charset("Cp284", "IBM284", new String[] {"ebcdic-cp-es", "csIBM284"}), - new Charset("Cp285", "IBM285", new String[] {"ebcdic-cp-gb", "csIBM285"}), - new Charset("Cp297", "IBM297", new String[] {"ebcdic-cp-fr", "csIBM297"}), - new Charset("Cp420", "IBM420", new String[] {"ebcdic-cp-ar1", "csIBM420"}), - new Charset("Cp424", "IBM424", new String[] {"ebcdic-cp-he", "csIBM424"}), - new Charset("Cp437", "IBM437", new String[] {"437", "csPC8CodePage437"}), - new Charset("Cp500", "IBM500", new String[] {"ebcdic-cp-be", "ebcdic-cp-ch", "csIBM500"}), - new Charset("Cp775", "IBM775", new String[] {"csPC775Baltic"}), - new Charset("Cp838", "IBM-Thai", new String[] {}), - new Charset("Cp850", "IBM850", new String[] {"850", "csPC850Multilingual"}), - new Charset("Cp852", "IBM852", new String[] {"852", "csPCp852"}), - new Charset("Cp855", "IBM855", new String[] {"855", "csIBM855"}), - new Charset("Cp857", "IBM857", new String[] {"857", "csIBM857"}), - new Charset("Cp858", "IBM00858", - new String[] {"CCSID00858", "CP00858", - "PC-Multilingual-850+euro"}), - new Charset("Cp860", "IBM860", new String[] {"860", "csIBM860"}), - new Charset("Cp861", "IBM861", new String[] {"861", "cp-is", "csIBM861"}), - new Charset("Cp862", "IBM862", new String[] {"862", "csPC862LatinHebrew"}), - new Charset("Cp863", "IBM863", new String[] {"863", "csIBM863"}), - new Charset("Cp864", "IBM864", new String[] {"cp864", "csIBM864"}), - new Charset("Cp865", "IBM865", new String[] {"865", "csIBM865"}), - new Charset("Cp866", "IBM866", new String[] {"866", "csIBM866"}), - new Charset("Cp868", "IBM868", new String[] {"cp-ar", "csIBM868"}), - new Charset("Cp869", "IBM869", new String[] {"cp-gr", "csIBM869"}), - new Charset("Cp870", "IBM870", new String[] {"ebcdic-cp-roece", "ebcdic-cp-yu", "csIBM870"}), - new Charset("Cp871", "IBM871", new String[] {"ebcdic-cp-is", "csIBM871"}), - new Charset("Cp918", "IBM918", new String[] {"ebcdic-cp-ar2", "csIBM918"}), - new Charset("Cp1026", "IBM1026", new String[] {"csIBM1026"}), - new Charset("Cp1047", "IBM1047", new String[] {"IBM-1047"}), - new Charset("Cp1140", "IBM01140", - new String[] {"CCSID01140", "CP01140", - "ebcdic-us-37+euro"}), - new Charset("Cp1141", "IBM01141", - new String[] {"CCSID01141", "CP01141", - "ebcdic-de-273+euro"}), - new Charset("Cp1142", "IBM01142", new String[] {"CCSID01142", "CP01142", "ebcdic-dk-277+euro", "ebcdic-no-277+euro"}), - new Charset("Cp1143", "IBM01143", new String[] {"CCSID01143", "CP01143", "ebcdic-fi-278+euro", "ebcdic-se-278+euro"}), - new Charset("Cp1144", "IBM01144", new String[] {"CCSID01144", "CP01144", "ebcdic-it-280+euro"}), - new Charset("Cp1145", "IBM01145", new String[] {"CCSID01145", "CP01145", "ebcdic-es-284+euro"}), - new Charset("Cp1146", "IBM01146", new String[] {"CCSID01146", "CP01146", "ebcdic-gb-285+euro"}), - new Charset("Cp1147", "IBM01147", new String[] {"CCSID01147", "CP01147", "ebcdic-fr-297+euro"}), - new Charset("Cp1148", "IBM01148", new String[] {"CCSID01148", "CP01148", "ebcdic-international-500+euro"}), - new Charset("Cp1149", "IBM01149", new String[] {"CCSID01149", "CP01149", "ebcdic-is-871+euro"}), - new Charset("Cp1250", "windows-1250", new String[] {}), - new Charset("Cp1251", "windows-1251", new String[] {}), - new Charset("Cp1252", "windows-1252", new String[] {}), - new Charset("Cp1253", "windows-1253", new String[] {}), - new Charset("Cp1254", "windows-1254", new String[] {}), - new Charset("Cp1255", "windows-1255", new String[] {}), - new Charset("Cp1256", "windows-1256", new String[] {}), - new Charset("Cp1257", "windows-1257", new String[] {}), - new Charset("Cp1258", "windows-1258", new String[] {}), - new Charset("ISO2022CN", "ISO-2022-CN", new String[] {}), - new Charset("ISO2022JP", "ISO-2022-JP", new String[] {"csISO2022JP", "JIS", "jis_encoding", "csjisencoding"}), - new Charset("ISO2022KR", "ISO-2022-KR", new String[] {"csISO2022KR"}), - new Charset("JIS_X0201", "JIS_X0201", new String[] {"X0201", "JIS0201", "csHalfWidthKatakana"}), - new Charset("JIS_X0212-1990", "JIS_X0212-1990", new String[] {"iso-ir-159", "x0212", "JIS0212", "csISO159JISX02121990"}), - new Charset("JIS_C6626-1983", "JIS_C6626-1983", new String[] {"x-JIS0208", "JIS0208", "csISO87JISX0208", "x0208", "JIS_X0208-1983", "iso-ir-87"}), - new Charset("SJIS", "Shift_JIS", new String[] {"MS_Kanji", "csShiftJIS", "shift-jis", "x-sjis", "pck"}), - new Charset("TIS620", "TIS-620", new String[] {}), - new Charset("MS932", "Windows-31J", new String[] {"windows-932", "csWindows31J", "x-ms-cp932"}), - new Charset("EUC_TW", "EUC-TW", new String[] {"x-EUC-TW", "cns11643", "euctw"}), - new Charset("x-Johab", "johab", new String[] {"johab", "cp1361", "ms1361", "ksc5601-1992", "ksc5601_1992"}), - new Charset("MS950_HKSCS", "", new String[] {}), - new Charset("MS874", "windows-874", new String[] {"cp874"}), - new Charset("MS949", "windows-949", new String[] {"windows949", "ms_949", "x-windows-949"}), - new Charset("MS950", "windows-950", new String[] {"x-windows-950"}), - - new Charset("Cp737", null, new String[] {}), - new Charset("Cp856", null, new String[] {}), - new Charset("Cp875", null, new String[] {}), - new Charset("Cp921", null, new String[] {}), - new Charset("Cp922", null, new String[] {}), - new Charset("Cp930", null, new String[] {}), - new Charset("Cp933", null, new String[] {}), - new Charset("Cp935", null, new String[] {}), - new Charset("Cp937", null, new String[] {}), - new Charset("Cp939", null, new String[] {}), - new Charset("Cp942", null, new String[] {}), - new Charset("Cp942C", null, new String[] {}), - new Charset("Cp943", null, new String[] {}), - new Charset("Cp943C", null, new String[] {}), - new Charset("Cp948", null, new String[] {}), - new Charset("Cp949", null, new String[] {}), - new Charset("Cp949C", null, new String[] {}), - new Charset("Cp950", null, new String[] {}), - new Charset("Cp964", null, new String[] {}), - new Charset("Cp970", null, new String[] {}), - new Charset("Cp1006", null, new String[] {}), - new Charset("Cp1025", null, new String[] {}), - new Charset("Cp1046", null, new String[] {}), - new Charset("Cp1097", null, new String[] {}), - new Charset("Cp1098", null, new String[] {}), - new Charset("Cp1112", null, new String[] {}), - new Charset("Cp1122", null, new String[] {}), - new Charset("Cp1123", null, new String[] {}), - new Charset("Cp1124", null, new String[] {}), - new Charset("Cp1381", null, new String[] {}), - new Charset("Cp1383", null, new String[] {}), - new Charset("Cp33722", null, new String[] {}), - new Charset("Big5_Solaris", null, new String[] {}), - new Charset("EUC_JP_LINUX", null, new String[] {}), - new Charset("EUC_JP_Solaris", null, new String[] {}), - new Charset("ISCII91", null, new String[] {"x-ISCII91", "iscii"}), - new Charset("ISO2022_CN_CNS", null, new String[] {}), - new Charset("ISO2022_CN_GB", null, new String[] {}), - new Charset("x-iso-8859-11", null, new String[] {}), - new Charset("JISAutoDetect", null, new String[] {}), - new Charset("MacArabic", null, new String[] {}), - new Charset("MacCentralEurope", null, new String[] {}), - new Charset("MacCroatian", null, new String[] {}), - new Charset("MacCyrillic", null, new String[] {}), - new Charset("MacDingbat", null, new String[] {}), - new Charset("MacGreek", "MacGreek", new String[] {}), - new Charset("MacHebrew", null, new String[] {}), - new Charset("MacIceland", null, new String[] {}), - new Charset("MacRoman", "MacRoman", new String[] {"Macintosh", "MAC", "csMacintosh"}), - new Charset("MacRomania", null, new String[] {}), - new Charset("MacSymbol", null, new String[] {}), - new Charset("MacThai", null, new String[] {}), - new Charset("MacTurkish", null, new String[] {}), - new Charset("MacUkraine", null, new String[] {}), - new Charset("UnicodeBig", null, new String[] {}), - new Charset("UnicodeLittle", null, new String[] {}) - }; - - /** - * Contains the canonical names of character sets which can be used to - * decode bytes into Java chars. - */ - private static TreeSet decodingSupported = null; - - /** - * Contains the canonical names of character sets which can be used to - * encode Java chars into bytes. - */ - private static TreeSet encodingSupported = null; - - /** - * Maps character set names to Charset objects. All possible names of - * a charset will be mapped to the Charset. - */ - private static HashMap charsetMap = null; - - static { - decodingSupported = new TreeSet(); - encodingSupported = new TreeSet(); - byte[] dummy = new byte[] {'d', 'u', 'm', 'm', 'y'}; - for (int i = 0; i < JAVA_CHARSETS.length; i++) { - try { - String s = new String(dummy, JAVA_CHARSETS[i].canonical); - decodingSupported.add(JAVA_CHARSETS[i].canonical.toLowerCase()); - } catch (UnsupportedOperationException e) { - } catch (UnsupportedEncodingException e) { - } - try { - "dummy".getBytes(JAVA_CHARSETS[i].canonical); - encodingSupported.add(JAVA_CHARSETS[i].canonical.toLowerCase()); - } catch (UnsupportedOperationException e) { - } catch (UnsupportedEncodingException e) { - } - } - - charsetMap = new HashMap(); - for (int i = 0; i < JAVA_CHARSETS.length; i++) { - Charset c = JAVA_CHARSETS[i]; - charsetMap.put(c.canonical.toLowerCase(), c); - if (c.mime != null) { - charsetMap.put(c.mime.toLowerCase(), c); - } - if (c.aliases != null) { - for (int j = 0; j < c.aliases.length; j++) { - charsetMap.put(c.aliases[j].toLowerCase(), c); - } - } - } - - if (log.isDebugEnabled()) { - log.debug("Character sets which support decoding: " - + decodingSupported); - log.debug("Character sets which support encoding: " - + encodingSupported); - } - } - - /** - * Determines if the VM supports encoding (chars to bytes) the - * specified character set. NOTE: the given character set name may - * not be known to the VM even if this method returns true. - * Use {@link #toJavaCharset(String)} to get the canonical Java character - * set name. - * - * @param charsetName the characters set name. - * @return true if encoding is supported, false - * otherwise. - */ - public static boolean isEncodingSupported(String charsetName) { - return encodingSupported.contains(charsetName.toLowerCase()); - } - - /** - * Determines if the VM supports decoding (bytes to chars) the - * specified character set. NOTE: the given character set name may - * not be known to the VM even if this method returns true. - * Use {@link #toJavaCharset(String)} to get the canonical Java character - * set name. - * - * @param charsetName the characters set name. - * @return true if decoding is supported, false - * otherwise. - */ - public static boolean isDecodingSupported(String charsetName) { - return decodingSupported.contains(charsetName.toLowerCase()); - } - - /** - * Gets the preferred MIME character set name for the specified - * character set or null if not known. - * - * @param charsetName the character set name to look for. - * @return the MIME preferred name or null if not known. - */ - public static String toMimeCharset(String charsetName) { - Charset c = (Charset) charsetMap.get(charsetName.toLowerCase()); - if (c != null) { - return c.mime; - } - return null; - } - - /** - * Gets the canonical Java character set name for the specified - * character set or null if not known. This should be - * called before doing any conversions using the Java API. NOTE: - * you must use {@link #isEncodingSupported(String)} or - * {@link #isDecodingSupported(String)} to make sure the returned - * Java character set is supported by the current VM. - * - * @param charsetName the character set name to look for. - * @return the canonical Java name or null if not known. - */ - public static String toJavaCharset(String charsetName) { - Charset c = (Charset) charsetMap.get(charsetName.toLowerCase()); - if (c != null) { - return c.canonical; - } - return null; - } - - public static java.nio.charset.Charset getCharset(String charsetName) { - String defaultCharset = "ISO-8859-1"; - - // Use the default chareset if given charset is null - if(charsetName == null) charsetName = defaultCharset; - - try { - return java.nio.charset.Charset.forName(charsetName); - } catch (IllegalCharsetNameException e) { - log.info("Illegal charset " + charsetName + ", fallback to " + defaultCharset + ": " + e); - // Use default charset on exception - return java.nio.charset.Charset.forName(defaultCharset); - } catch (UnsupportedCharsetException ex) { - log.info("Unsupported charset " + charsetName + ", fallback to " + defaultCharset + ": " + ex); - // Use default charset on exception - return java.nio.charset.Charset.forName(defaultCharset); - } - - } - /* - * Uncomment the code below and run the main method to regenerate the - * Javadoc table above when the known charsets change. - */ - - /* - private static String dumpHtmlTable() { - LinkedList l = new LinkedList(Arrays.asList(JAVA_CHARSETS)); - Collections.sort(l); - StringBuffer sb = new StringBuffer(); - sb.append(" * \n"); - sb.append(" * \n"); - sb.append(" * \n"); - sb.append(" * \n"); - sb.append(" * \n"); - sb.append(" * \n"); - - for (Iterator it = l.iterator(); it.hasNext();) { - Charset c = (Charset) it.next(); - sb.append(" * \n"); - sb.append(" * \n"); - sb.append(" * \n"); - sb.append(" * \n"); - sb.append(" * \n"); - } - sb.append(" *
Canonical (Java) nameMIME preferredAliases
" + c.canonical + "" + (c.mime == null ? "?" : c.mime)+ ""); - for (int i = 0; c.aliases != null && i < c.aliases.length; i++) { - sb.append(c.aliases[i] + " "); - } - sb.append("
\n"); - return sb.toString(); - } - - public static void main(String[] args) { - System.out.println(dumpHtmlTable()); - }*/ -} diff --git a/src/org/apache/james/mime4j/util/PartialInputStream.java b/src/org/apache/james/mime4j/util/PartialInputStream.java deleted file mode 100644 index a5ac0596d..000000000 --- a/src/org/apache/james/mime4j/util/PartialInputStream.java +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - - -package org.apache.james.mime4j.util; - -import java.io.InputStream; -import java.io.IOException; - -public class PartialInputStream extends PositionInputStream { - private final long limit; - - public PartialInputStream(InputStream inputStream, long offset, long length) throws IOException { - super(inputStream); - inputStream.skip(offset); - this.limit = offset + length; - } - - public int available() throws IOException { - return Math.min(super.available(), getBytesLeft()); - } - - public int read() throws IOException { - if (limit > position) - return super.read(); - else - return -1; - } - - public int read(byte b[]) throws IOException { - return read(b, 0, b.length); - } - - public int read(byte b[], int off, int len) throws IOException { - len = Math.min(len, getBytesLeft()); - return super.read(b, off, len); //To change body of overridden methods use File | Settings | File Templates. - } - - public long skip(long n) throws IOException { - n = Math.min(n, getBytesLeft()); - return super.skip(n); //To change body of overridden methods use File | Settings | File Templates. - } - - private int getBytesLeft() { - return (int)Math.min(Integer.MAX_VALUE, limit - position); - } -} diff --git a/src/org/apache/james/mime4j/util/PositionInputStream.java b/src/org/apache/james/mime4j/util/PositionInputStream.java deleted file mode 100644 index 9fcd21d0c..000000000 --- a/src/org/apache/james/mime4j/util/PositionInputStream.java +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - - -package org.apache.james.mime4j.util; - -import java.io.InputStream; -import java.io.IOException; - -public class PositionInputStream extends InputStream { - - private final InputStream inputStream; - protected long position = 0; - private long markedPosition = 0; - - public PositionInputStream(InputStream inputStream) { - this.inputStream = inputStream; - } - - public long getPosition() { - return position; - } - - public int available() throws IOException { - return inputStream.available(); - } - - public int read() throws IOException { - int b = inputStream.read(); - if (b != -1) - position++; - return b; - } - - public void close() throws IOException { - inputStream.close(); - } - - public void reset() throws IOException { - inputStream.reset(); - position = markedPosition; - } - - public boolean markSupported() { - return inputStream.markSupported(); - } - - public void mark(int readlimit) { - inputStream.mark(readlimit); - markedPosition = position; - } - - public long skip(long n) throws IOException { - final long c = inputStream.skip(n); - position += c; - return c; - } - - public int read(byte b[]) throws IOException { - final int c = inputStream.read(b); - position += c; - return c; - } - - public int read(byte b[], int off, int len) throws IOException { - final int c = inputStream.read(b, off, len); - position += c; - return c; - } - -} diff --git a/src/org/apache/james/mime4j/util/SimpleTempStorage.java b/src/org/apache/james/mime4j/util/SimpleTempStorage.java deleted file mode 100644 index 7ca0371a2..000000000 --- a/src/org/apache/james/mime4j/util/SimpleTempStorage.java +++ /dev/null @@ -1,236 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.util; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Random; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * - * @version $Id: SimpleTempStorage.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -public class SimpleTempStorage extends TempStorage { - private static Log log = LogFactory.getLog(SimpleTempStorage.class); - - private TempPath rootPath = null; - private Random random = new Random(); - - /** - * Creates a new SimpleTempStorageManager instance. - */ - public SimpleTempStorage() { - rootPath = new SimpleTempPath(System.getProperty("java.io.tmpdir")); - } - - private TempPath createTempPath(TempPath parent, String prefix) - throws IOException { - - if (prefix == null) { - prefix = ""; - } - - File p = null; - int count = 1000; - do { - long n = Math.abs(random.nextLong()); - p = new File(parent.getAbsolutePath(), prefix + n); - count--; - } while (p.exists() && count > 0); - - if (p.exists() || !p.mkdirs()) { - log.error("Unable to mkdirs on " + p.getAbsolutePath()); - throw new IOException("Creating dir '" - + p.getAbsolutePath() + "' failed."); - } - - return new SimpleTempPath(p); - } - - private TempFile createTempFile(TempPath parent, String prefix, - String suffix) throws IOException { - - if (prefix == null) { - prefix = ""; - } - if (suffix == null) { - suffix = ".tmp"; - } - - File f = null; - - int count = 1000; - synchronized (this) { - do { - long n = Math.abs(random.nextLong()); - f = new File(parent.getAbsolutePath(), prefix + n + suffix); - count--; - } while (f.exists() && count > 0); - - if (f.exists()) { - throw new IOException("Creating temp file failed: " - + "Unable to find unique file name"); - } - - try { - f.createNewFile(); - } catch (IOException e) { - throw new IOException("Creating dir '" - + f.getAbsolutePath() + "' failed."); - } - } - - return new SimpleTempFile(f); - } - - /** - * @see org.apache.james.mime4j.util.TempStorage#getRootTempPath() - */ - public TempPath getRootTempPath() { - return rootPath; - } - - private class SimpleTempPath implements TempPath { - private File path = null; - - private SimpleTempPath(String path) { - this.path = new File(path); - } - - private SimpleTempPath(File path) { - this.path = path; - } - - /** - * @see org.apache.james.mime4j.util.TempPath#createTempFile() - */ - public TempFile createTempFile() throws IOException { - return SimpleTempStorage.this.createTempFile(this, null, null); - } - - /** - * @see org.apache.james.mime4j.util.TempPath#createTempFile(java.lang.String, java.lang.String) - */ - public TempFile createTempFile(String prefix, String suffix) - throws IOException { - - return SimpleTempStorage.this.createTempFile(this, prefix, suffix); - } - - /** - * @see org.apache.james.mime4j.util.TempPath#createTempFile(java.lang.String, java.lang.String, boolean) - */ - public TempFile createTempFile(String prefix, String suffix, - boolean allowInMemory) - throws IOException { - - return SimpleTempStorage.this.createTempFile(this, prefix, suffix); - } - - /** - * @see org.apache.james.mime4j.util.TempPath#getAbsolutePath() - */ - public String getAbsolutePath() { - return path.getAbsolutePath(); - } - - /** - * Do nothing - */ - public void delete() { - } - - /** - * @see org.apache.james.mime4j.util.TempPath#createTempPath() - */ - public TempPath createTempPath() throws IOException { - return SimpleTempStorage.this.createTempPath(this, null); - } - - /** - * @see org.apache.james.mime4j.util.TempPath#createTempPath(java.lang.String) - */ - public TempPath createTempPath(String prefix) throws IOException { - return SimpleTempStorage.this.createTempPath(this, prefix); - } - - } - - private class SimpleTempFile implements TempFile { - private File file = null; - - private SimpleTempFile(File file) { - this.file = file; - this.file.deleteOnExit(); - } - - /** - * @see org.apache.james.mime4j.util.TempFile#getInputStream() - */ - public InputStream getInputStream() throws IOException { - return new BufferedInputStream(new FileInputStream(file)); - } - - /** - * @see org.apache.james.mime4j.util.TempFile#getOutputStream() - */ - public OutputStream getOutputStream() throws IOException { - return new BufferedOutputStream(new FileOutputStream(file)); - } - - /** - * @see org.apache.james.mime4j.util.TempFile#getAbsolutePath() - */ - public String getAbsolutePath() { - return file.getAbsolutePath(); - } - - /** - * Do nothing - */ - public void delete() { - // Not implementated - } - - /** - * @see org.apache.james.mime4j.util.TempFile#isInMemory() - */ - public boolean isInMemory() { - return false; - } - - /** - * @see org.apache.james.mime4j.util.TempFile#length() - */ - public long length() { - return file.length(); - } - - } -} diff --git a/src/org/apache/james/mime4j/util/TempFile.java b/src/org/apache/james/mime4j/util/TempFile.java deleted file mode 100644 index f67e1e93e..000000000 --- a/src/org/apache/james/mime4j/util/TempFile.java +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.util; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * @version $Id: TempFile.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $ - */ -public interface TempFile { - /** - * Gets an InputStream to read bytes from this temporary file. - * NOTE: The stream should NOT be wrapped in - * BufferedInputStream by the caller. If the implementing - * TempFile creates a FileInputStream or any - * other stream which would benefit from being buffered it's the - * TempFile's responsibility to wrap it. - * - * @return the stream. - * @throws IOException - */ - InputStream getInputStream() throws IOException; - - /** - * Gets an OutputStream to write bytes to this temporary file. - * NOTE: The stream should NOT be wrapped in - * BufferedOutputStream by the caller. If the implementing - * TempFile creates a FileOutputStream or any - * other stream which would benefit from being buffered it's the - * TempFile's responsibility to wrap it. - * - * @return the stream. - * @throws IOException - */ - OutputStream getOutputStream() throws IOException; - - /** - * Returns the absolute path including file name of this - * TempFile. The path may be null if this is - * an in-memory file. - * - * @return the absolute path. - */ - String getAbsolutePath(); - - /** - * Deletes this file as soon as possible. - */ - void delete(); - - /** - * Determines if this is an in-memory file. - * - * @return true if this file is currently in memory, - * false otherwise. - */ - boolean isInMemory(); - - /** - * Gets the length of this temporary file. - * - * @return the length. - */ - long length(); -} diff --git a/src/org/apache/james/mime4j/util/TempPath.java b/src/org/apache/james/mime4j/util/TempPath.java deleted file mode 100644 index 3b55aa6db..000000000 --- a/src/org/apache/james/mime4j/util/TempPath.java +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.util; - -import java.io.IOException; - -/** - * - * @version $Id: TempPath.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -public interface TempPath { - TempPath createTempPath() throws IOException; - TempPath createTempPath(String prefix) throws IOException; - - /** - * Creates a new temporary file. Wheter it will be be created in memory - * or on disk is up to to the implementation. - * The prefix will be empty and the suffix will be - * .tmp if created on disk. - * - * @return the temporary file. - */ - TempFile createTempFile() throws IOException; - - /** - * Creates a new temporary file. Wheter it will be be created in memory - * or on disk is up to to the implementation. - * The prefix and suffix can be set by the user. - * - * @param prefix the prefix to use. null gives no prefix. - * @param suffix the suffix to use. null gives - * .tmp. - * @return the temporary file. - */ - TempFile createTempFile(String prefix, String suffix) throws IOException; - - /** - * Creates a new temporary file. Wheter it will be be created in memory - * or on disk can be specified using the allowInMemory - * parameter. If the implementation doesn't support in-memory files - * the new file will be created on disk. - * The prefix and suffix can be set by the user. - * - * @param prefix the prefix to use. null gives no prefix. - * @param suffix the suffix to use. null gives - * .tmp. - * @param allowInMemory if true the file MIGHT be created in - * memory if supported by the implentation. If false the - * file MUST be created on disk. - * @return the temporary file. - */ - TempFile createTempFile(String prefix, String suffix, - boolean allowInMemory) throws IOException; - String getAbsolutePath(); - void delete(); -} diff --git a/src/org/apache/james/mime4j/util/TempStorage.java b/src/org/apache/james/mime4j/util/TempStorage.java deleted file mode 100644 index ca951531a..000000000 --- a/src/org/apache/james/mime4j/util/TempStorage.java +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.mime4j.util; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * - * @version $Id: TempStorage.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $ - */ -public abstract class TempStorage { - private static Log log = LogFactory.getLog(TempStorage.class); - private static TempStorage inst = null; - - static { - - String clazz = System.getProperty("org.apache.james.mime4j.tempStorage"); - try { - - if (inst != null) { - inst = (TempStorage) Class.forName(clazz).newInstance(); - } - - } catch (Throwable t) { - log.warn("Unable to create or instantiate TempStorage class '" - + clazz + "' using SimpleTempStorage instead", t); - } - - if (inst == null) { - inst = new SimpleTempStorage(); - } - } - - /** - * Gets the root temporary path which should be used to - * create new temporary paths or files. - * - * @return the root temporary path. - */ - public abstract TempPath getRootTempPath(); - - public static TempStorage getInstance() { - return inst; - } - - public static void setInstance(TempStorage inst) { - if (inst == null) { - throw new NullPointerException("inst"); - } - TempStorage.inst = inst; - } -}