You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by Norman Maurer <no...@apache.org> on 2010/08/30 18:20:04 UTC

Re: svn commit: r990364 [2/5] - in /james/imap/trunk: ./ decode/ decode/src/ message/ message/src/main/java/org/apache/james/imap/decode/ message/src/main/java/org/apache/james/imap/decode/base/ message/src/main/java/org/apache/james/imap/decode/main

Hi Eric,

these changes seems to mess up with how svn should be used.. maybe its
the stupid eclipse plugin who knows ;) Could you revert the changes
and better use svn cp so we don't loose all the history ?

Thx,
Norman

2010/8/28  <er...@apache.org>:
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/AbstractImapCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/AbstractImapCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/AbstractImapCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/AbstractImapCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,774 @@
> +/****************************************************************
> + * 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.imap.decode.base;
> +
> +import java.io.ByteArrayOutputStream;
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.nio.ByteBuffer;
> +import java.nio.CharBuffer;
> +import java.nio.charset.CharacterCodingException;
> +import java.nio.charset.Charset;
> +import java.nio.charset.CharsetDecoder;
> +import java.nio.charset.CoderResult;
> +import java.nio.charset.CodingErrorAction;
> +import java.nio.charset.MalformedInputException;
> +import java.nio.charset.UnmappableCharacterException;
> +import java.util.ArrayList;
> +import java.util.Date;
> +
> +import javax.mail.Flags;
> +
> +import org.apache.commons.io.IOUtils;
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.api.display.HumanReadableText;
> +import org.apache.james.imap.api.message.IdRange;
> +import org.apache.james.imap.api.message.request.DayMonthYear;
> +import org.apache.james.imap.api.message.response.StatusResponseFactory;
> +import org.apache.james.imap.decode.DecoderUtils;
> +import org.apache.james.imap.decode.ImapCommandParser;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.MessagingImapCommandParser;
> +import org.apache.james.imap.decode.DecodingException;
> +
> +/**
> + * <p>
> + * <strong>Note:</strong>
> + * </p>
> + *
> + * @version $Revision: 109034 $
> + */
> +public abstract class AbstractImapCommandParser implements ImapCommandParser, MessagingImapCommandParser {
> +    private static final int QUOTED_BUFFER_INITIAL_CAPACITY = 64;
> +
> +    private static final Charset US_ASCII = Charset.forName("US-ASCII");
> +
> +    private final ImapCommand command;
> +
> +    private ImapMessageFactory messageFactory;
> +
> +    private StatusResponseFactory statusResponseFactory;
> +
> +    public AbstractImapCommandParser(final ImapCommand command) {
> +        super();
> +        this.command = command;
> +    }
> +
> +    public ImapCommand getCommand() {
> +        return command;
> +    }
> +
> +
> +    /**
> +     * @see org.apache.james.imap.decode.MessagingImapCommandParser#getMessageFactory()
> +     */
> +    public ImapMessageFactory getMessageFactory() {
> +        return messageFactory;
> +    }
> +
> +    /**
> +     * @see org.apache.james.imap.decode.MessagingImapCommandParser#setMessageFactory(org.apache.james.imap.api.ImapMessageFactory)
> +     */
> +    public void setMessageFactory(ImapMessageFactory messageFactory) {
> +        this.messageFactory = messageFactory;
> +    }
> +
> +    public final StatusResponseFactory getStatusResponseFactory() {
> +        return statusResponseFactory;
> +    }
> +
> +    public final void setStatusResponseFactory(
> +            StatusResponseFactory statusResponseFactory) {
> +        this.statusResponseFactory = statusResponseFactory;
> +    }
> +
> +    /**
> +     * Parses a request into a command message for later processing.
> +     *
> +     * @param request
> +     *            <code>ImapRequestLineReader</code>, not null
> +     * @return <code>ImapCommandMessage</code>, not null
> +     */
> +    public final ImapMessage parse(ImapRequestLineReader request, String tag, Log logger) {
> +        ImapMessage result;
> +        try {
> +
> +            ImapMessage message = decode(command, request, tag, logger);
> +            result = message;
> +
> +        } catch (DecodingException e) {
> +            logger.debug("Cannot parse protocol ", e);
> +            e.printStackTrace();
> +            result = messageFactory.taggedBad(tag, command, e.getKey());
> +        }
> +        return result;
> +    }
> +
> +    /**
> +     * Parses a request into a command message for later processing.
> +     * @param command
> +     *            <code>ImapCommand</code> to be parsed, not null
> +     * @param request
> +     *            <code>ImapRequestLineReader</code>, not null
> +     * @param tag command tag, not null
> +     * @param logger TODO
> +     * @param logger TODO
> +     * @return <code>ImapCommandMessage</code>, not null
> +     * @throws DecodingException
> +     *             if the request cannot be parsed
> +     */
> +    protected abstract ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException;
> +
> +    /**
> +     * Reads an argument of type "atom" from the request.
> +     */
> +    public static String atom(ImapRequestLineReader request)
> +            throws DecodingException {
> +        return consumeWord(request, new ATOM_CHARValidator());
> +    }
> +
> +    /**
> +     * Reads a command "tag" from the request.
> +     */
> +    public static String tag(ImapRequestLineReader request)
> +            throws DecodingException {
> +        CharacterValidator validator = new TagCharValidator();
> +        return consumeWord(request, validator);
> +    }
> +
> +    /**
> +     * Reads an argument of type "astring" from the request.
> +     */
> +    public String astring(ImapRequestLineReader request)
> +            throws DecodingException {
> +        return astring(request, null);
> +    }
> +
> +    /**
> +     * Reads an argument of type "astring" from the request.
> +     */
> +    public String astring(ImapRequestLineReader request, Charset charset)
> +            throws DecodingException {
> +        char next = request.nextWordChar();
> +        switch (next) {
> +            case '"':
> +                return consumeQuoted(request, charset);
> +            case '{':
> +                return consumeLiteral(request, charset);
> +            default:
> +                return atom(request);
> +        }
> +    }
> +
> +    /**
> +     * Reads an argument of type "nstring" from the request.
> +     */
> +    public String nstring(ImapRequestLineReader request)
> +            throws DecodingException {
> +        char next = request.nextWordChar();
> +        switch (next) {
> +            case '"':
> +                return consumeQuoted(request);
> +            case '{':
> +                return consumeLiteral(request, null);
> +            default:
> +                String value = atom(request);
> +                if ("NIL".equals(value)) {
> +                    return null;
> +                } else {
> +                    throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS,
> +                            "Invalid nstring value: valid values are '\"...\"', '{12} CRLF *CHAR8', and 'NIL'.");
> +                }
> +        }
> +    }
> +
> +    /**
> +     * Reads a "mailbox" argument from the request. Not implemented *exactly* as
> +     * per spec, since a quoted or literal "inbox" still yeilds "INBOX" (ie
> +     * still case-insensitive if quoted or literal). I think this makes sense.
> +     *
> +     * mailbox ::= "INBOX" / astring ;; INBOX is case-insensitive. All case
> +     * variants of ;; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX ;; not
> +     * as an astring.
> +     */
> +    public String mailbox(ImapRequestLineReader request)
> +            throws DecodingException {
> +        String mailbox = astring(request);
> +        if (mailbox.equalsIgnoreCase(ImapConstants.INBOX_NAME)) {
> +            return ImapConstants.INBOX_NAME;
> +        } else {
> +            return mailbox;
> +        }
> +    }
> +
> +    /**
> +     * Reads one <code>date</code> argument from the request.
> +     *
> +     * @param request
> +     *            <code>ImapRequestLineReader</code>, not null
> +     * @return <code>DayMonthYear</code>, not null
> +     * @throws DecodingException
> +     */
> +    public DayMonthYear date(ImapRequestLineReader request)
> +            throws DecodingException {
> +
> +        final char one = request.consume();
> +        final char two = request.consume();
> +        final int day;
> +        if (two == '-') {
> +            day = DecoderUtils.decodeFixedDay(' ', one);
> +        } else {
> +            day = DecoderUtils.decodeFixedDay(one, two);
> +            nextIsDash(request);
> +        }
> +
> +        final char monthFirstChar = request.consume();
> +        final char monthSecondChar = request.consume();
> +        final char monthThirdChar = request.consume();
> +        final int month = DecoderUtils.decodeMonth(monthFirstChar,
> +                monthSecondChar, monthThirdChar) + 1;
> +        nextIsDash(request);
> +        final char milleniumChar = request.consume();
> +        final char centuryChar = request.consume();
> +        final char decadeChar = request.consume();
> +        final char yearChar = request.consume();
> +        final int year = DecoderUtils.decodeYear(milleniumChar, centuryChar,
> +                decadeChar, yearChar);
> +        final DayMonthYear result = new DayMonthYear(day, month, year);
> +        return result;
> +    }
> +
> +    private void nextIsDash(ImapRequestLineReader request)
> +            throws DecodingException {
> +        final char next = request.consume();
> +        if (next != '-') {
> +            throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Expected dash but was " + next);
> +        }
> +    }
> +
> +    /**
> +     * Reads a "date-time" argument from the request.
> +     */
> +    public Date dateTime(ImapRequestLineReader request)
> +            throws DecodingException {
> +        char next = request.nextWordChar();
> +        String dateString;
> +        if (next == '"') {
> +            dateString = consumeQuoted(request);
> +        } else {
> +            throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "DateTime values must be quoted.");
> +        }
> +
> +        return DecoderUtils.decodeDateTime(dateString);
> +    }
> +
> +    /**
> +     * Reads the next "word from the request, comprising all characters up to
> +     * the next SPACE. Characters are tested by the supplied CharacterValidator,
> +     * and an exception is thrown if invalid characters are encountered.
> +     */
> +    protected static String consumeWord(ImapRequestLineReader request,
> +            CharacterValidator validator) throws DecodingException {
> +        StringBuffer atom = new StringBuffer();
> +
> +        char next = request.nextWordChar();
> +        while (!isWhitespace(next)) {
> +            if (validator.isValid(next)) {
> +                atom.append(next);
> +                request.consume();
> +            } else {
> +                throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Invalid character: '" + next + "'");
> +            }
> +            next = request.nextChar();
> +        }
> +        return atom.toString();
> +    }
> +
> +    private static boolean isWhitespace(char next) {
> +        return (next == ' ' || next == '\n' || next == '\r' || next == '\t');
> +    }
> +
> +    /**
> +     * Reads an argument of type "literal" from the request, in the format: "{"
> +     * charCount "}" CRLF *CHAR8 Note before calling, the request should be
> +     * positioned so that nextChar is '{'. Leading whitespace is not skipped in
> +     * this method.
> +     *
> +     * @param charset ,
> +     *            or null for <code>US-ASCII</code>
> +     */
> +    protected String consumeLiteral(final ImapRequestLineReader request,
> +            final Charset charset) throws DecodingException {
> +        if (charset == null) {
> +            return consumeLiteral(request, US_ASCII);
> +        } else {
> +            ByteArrayOutputStream out = new ByteArrayOutputStream();
> +            try {
> +                IOUtils.copy(consumeLiteral(request),out);
> +            } catch (IOException e) {
> +                throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding",  e);
> +            }
> +            final byte[] bytes = out.toByteArray();
> +            final ByteBuffer buffer = ByteBuffer.wrap(bytes);
> +            return decode(charset, buffer);
> +        }
> +    }
> +
> +    protected InputStream  consumeLiteral(final ImapRequestLineReader request) throws DecodingException {
> +        // The 1st character must be '{'
> +        consumeChar(request, '{');
> +
> +        StringBuffer digits = new StringBuffer();
> +        char next = request.nextChar();
> +        while (next != '}' && next != '+') {
> +            digits.append(next);
> +            request.consume();
> +            next = request.nextChar();
> +        }
> +
> +        // If the number is *not* suffixed with a '+', we *are* using a
> +        // synchronized literal,
> +        // and we need to send command continuation request before reading
> +        // data.
> +        boolean synchronizedLiteral = true;
> +        // '+' indicates a non-synchronized literal (no command continuation
> +        // request)
> +        if (next == '+') {
> +            synchronizedLiteral = false;
> +            consumeChar(request, '+');
> +        }
> +
> +        // Consume the '}' and the newline
> +        consumeChar(request, '}');
> +        consumeCRLF(request);
> +
> +        if (synchronizedLiteral) {
> +            request.commandContinuationRequest();
> +        }
> +
> +        final int size = Integer.parseInt(digits.toString());
> +        return request.read(size);
> +    }
> +
> +    private String decode(final Charset charset, final ByteBuffer buffer)
> +            throws DecodingException {
> +        try {
> +            final String result = charset.newDecoder().onMalformedInput(
> +                    CodingErrorAction.REPORT).onUnmappableCharacter(
> +                    CodingErrorAction.REPORT).decode(buffer).toString();
> +            return result;
> +
> +        } catch (IllegalStateException e) {
> +            throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding", e);
> +        } catch (MalformedInputException e) {
> +            throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding", e);
> +        } catch (UnmappableCharacterException e) {
> +            throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding", e);
> +        } catch (CharacterCodingException e) {
> +            throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding", e);
> +        }
> +    }
> +
> +    /**
> +     * Consumes a CRLF from the request.
> +     * TODO: This is too liberal, the spec insists on \r\n for new lines.
> +     *
> +     * @param request
> +     * @throws DecodingException
> +     */
> +    private void consumeCRLF(ImapRequestLineReader request)
> +            throws DecodingException {
> +        char next = request.nextChar();
> +        if (next != '\n') {
> +            consumeChar(request, '\r');
> +        }
> +        consumeChar(request, '\n');
> +    }
> +
> +    /**
> +     * Consumes the next character in the request, checking that it matches the
> +     * expected one. This method should be used when the
> +     */
> +    protected void consumeChar(ImapRequestLineReader request, char expected)
> +            throws DecodingException {
> +        char consumed = request.consume();
> +        if (consumed != expected) {
> +            throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS,
> +                    "Expected:'" + expected + "' found:'" + consumed + "'");
> +        }
> +    }
> +
> +    /**
> +     * Reads a quoted string value from the request.
> +     */
> +    protected String consumeQuoted(ImapRequestLineReader request)
> +            throws DecodingException {
> +        return consumeQuoted(request, null);
> +    }
> +
> +    /**
> +     * Reads a quoted string value from the request.
> +     */
> +    protected String consumeQuoted(ImapRequestLineReader request,
> +            Charset charset) throws DecodingException {
> +        if (charset == null) {
> +            return consumeQuoted(request, US_ASCII);
> +        } else {
> +            // The 1st character must be '"'
> +            consumeChar(request, '"');
> +            final QuotedStringDecoder decoder = new QuotedStringDecoder(charset);
> +            final String result = decoder.decode(request);
> +            consumeChar(request, '"');
> +            return result;
> +        }
> +    }
> +
> +    /**
> +     * Reads a "flags" argument from the request.
> +     */
> +    public Flags flagList(ImapRequestLineReader request)
> +            throws DecodingException {
> +        Flags flags = new Flags();
> +        request.nextWordChar();
> +        consumeChar(request, '(');
> +        CharacterValidator validator = new NoopCharValidator();
> +        String nextWord = consumeWord(request, validator);
> +        while (!nextWord.endsWith(")")) {
> +            DecoderUtils.setFlag(nextWord, flags);
> +            nextWord = consumeWord(request, validator);
> +        }
> +        // Got the closing ")", may be attached to a word.
> +        if (nextWord.length() > 1) {
> +            int parenIndex = nextWord.indexOf(')');
> +            if (parenIndex > 0) {
> +                final String nextFlag = nextWord.substring(0, parenIndex);
> +                DecoderUtils.setFlag(nextFlag, flags);
> +            }
> +        }
> +
> +        return flags;
> +    }
> +
> +    /**
> +     * Reads an argument of type "number" from the request.
> +     */
> +    public long number(ImapRequestLineReader request) throws DecodingException {
> +        return readDigits(request, 0, 0, true);
> +    }
> +
> +    private long readDigits(final ImapRequestLineReader request, int add,
> +            final long total, final boolean first) throws DecodingException {
> +        final char next;
> +        if (first) {
> +            next = request.nextWordChar();
> +        } else {
> +            request.consume();
> +            next = request.nextChar();
> +        }
> +        final long currentTotal = (10 * total) + add;
> +        switch (next) {
> +            case '0':
> +                return readDigits(request, 0, currentTotal, false);
> +            case '1':
> +                return readDigits(request, 1, currentTotal, false);
> +            case '2':
> +                return readDigits(request, 2, currentTotal, false);
> +            case '3':
> +                return readDigits(request, 3, currentTotal, false);
> +            case '4':
> +                return readDigits(request, 4, currentTotal, false);
> +            case '5':
> +                return readDigits(request, 5, currentTotal, false);
> +            case '6':
> +                return readDigits(request, 6, currentTotal, false);
> +            case '7':
> +                return readDigits(request, 7, currentTotal, false);
> +            case '8':
> +                return readDigits(request, 8, currentTotal, false);
> +            case '9':
> +                return readDigits(request, 9, currentTotal, false);
> +            case '.':
> +            case ' ':
> +            case '>':
> +            case '\r':
> +            case '\n':
> +            case '\t':
> +                return currentTotal;
> +            default:
> +                throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Expected a digit but was " + next);
> +        }
> +    }
> +
> +    /**
> +     * Reads an argument of type "nznumber" (a non-zero number) (NOTE this isn't
> +     * strictly as per the spec, since the spec disallows numbers such as "0123"
> +     * as nzNumbers (although it's ok as a "number". I think the spec is a bit
> +     * shonky.)
> +     */
> +    public long nzNumber(ImapRequestLineReader request)
> +            throws DecodingException {
> +        long number = number(request);
> +        if (number == 0) {
> +            throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Zero value not permitted.");
> +        }
> +        return number;
> +    }
> +
> +    private static boolean isCHAR(char chr) {
> +        return (chr >= 0x01 && chr <= 0x7f);
> +    }
> +
> +    protected static boolean isListWildcard(char chr) {
> +        return (chr == '*' || chr == '%');
> +    }
> +
> +    private static boolean isQuotedSpecial(char chr) {
> +        return (chr == '"' || chr == '\\');
> +    }
> +
> +    /**
> +     * Consumes the request up to and including the eno-of-line.
> +     *
> +     * @param request
> +     *            The request
> +     * @throws DecodingException
> +     *             If characters are encountered before the endLine.
> +     */
> +    public void endLine(ImapRequestLineReader request) throws DecodingException {
> +        request.eol();
> +    }
> +
> +    /**
> +     * Reads a "message set" argument, and parses into an IdSet. Currently only
> +     * supports a single range of values.
> +     */
> +    public IdRange[] parseIdRange(ImapRequestLineReader request)
> +            throws DecodingException {
> +        CharacterValidator validator = new MessageSetCharValidator();
> +        String nextWord = consumeWord(request, validator);
> +
> +        int commaPos = nextWord.indexOf(',');
> +        if (commaPos == -1) {
> +            return new IdRange[] { parseRange(nextWord) };
> +        }
> +
> +        ArrayList<IdRange> rangeList = new ArrayList<IdRange>();
> +        int pos = 0;
> +        while (commaPos != -1) {
> +            String range = nextWord.substring(pos, commaPos);
> +            IdRange set = parseRange(range);
> +            rangeList.add(set);
> +
> +            pos = commaPos + 1;
> +            commaPos = nextWord.indexOf(',', pos);
> +        }
> +        String range = nextWord.substring(pos);
> +        rangeList.add(parseRange(range));
> +        return (IdRange[]) rangeList.toArray(new IdRange[rangeList.size()]);
> +    }
> +
> +    private IdRange parseRange(String range) throws DecodingException {
> +        int pos = range.indexOf(':');
> +        try {
> +            if (pos == -1) {
> +                long value = parseLong(range);
> +                return new IdRange(value);
> +            } else {
> +                long lowVal = parseLong(range.substring(0, pos));
> +                long highVal = parseLong(range.substring(pos + 1));
> +                return new IdRange(lowVal, highVal);
> +            }
> +        } catch (NumberFormatException e) {
> +            throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Invalid message set.", e);
> +        }
> +    }
> +
> +    private long parseLong(String value) {
> +        if (value.length() == 1 && value.charAt(0) == '*') {
> +            return Long.MAX_VALUE;
> +        }
> +        return Long.parseLong(value);
> +    }
> +
> +    /**
> +     * Provides the ability to ensure characters are part of a permitted set.
> +     */
> +    public interface CharacterValidator {
> +        /**
> +         * Validates the supplied character.
> +         *
> +         * @param chr
> +         *            The character to validate.
> +         * @return <code>true</code> if chr is valid, <code>false</code> if
> +         *         not.
> +         */
> +        boolean isValid(char chr);
> +    }
> +
> +    public static class NoopCharValidator implements CharacterValidator {
> +        public boolean isValid(char chr) {
> +            return true;
> +        }
> +    }
> +
> +    public static class ATOM_CHARValidator implements CharacterValidator {
> +        public boolean isValid(char chr) {
> +            return (isCHAR(chr) && !isAtomSpecial(chr) && !isListWildcard(chr) && !isQuotedSpecial(chr));
> +        }
> +
> +        private boolean isAtomSpecial(char chr) {
> +            return (chr == '(' || chr == ')' || chr == '{' || chr == ' ' || chr == Character.CONTROL);
> +        }
> +    }
> +
> +    public static class TagCharValidator extends ATOM_CHARValidator {
> +        public boolean isValid(char chr) {
> +            if (chr == '+')
> +                return false;
> +            return super.isValid(chr);
> +        }
> +    }
> +
> +    public static class MessageSetCharValidator implements CharacterValidator {
> +        public boolean isValid(char chr) {
> +            return (isDigit(chr) || chr == ':' || chr == '*' || chr == ',');
> +        }
> +
> +        private boolean isDigit(char chr) {
> +            return '0' <= chr && chr <= '9';
> +        }
> +    }
> +
> +    /**
> +     * Decodes contents of a quoted string. Charset aware. One shot, not thread
> +     * safe.
> +     */
> +    private static class QuotedStringDecoder {
> +        /** Decoder suitable for charset */
> +        private final CharsetDecoder decoder;
> +
> +        /** byte buffer will be filled then flushed to character buffer */
> +        private final ByteBuffer buffer;
> +
> +        /** character buffer may be dynamically resized */
> +        CharBuffer charBuffer;
> +
> +        public QuotedStringDecoder(Charset charset) {
> +            decoder = charset.newDecoder();
> +            buffer = ByteBuffer.allocate(QUOTED_BUFFER_INITIAL_CAPACITY);
> +            charBuffer = CharBuffer.allocate(QUOTED_BUFFER_INITIAL_CAPACITY);
> +        }
> +
> +        public String decode(ImapRequestLineReader request)
> +                throws DecodingException {
> +            try {
> +                decoder.reset();
> +                char next = request.nextChar();
> +                while (next != '"') {
> +                    // fill up byte buffer before decoding
> +                    if (!buffer.hasRemaining()) {
> +                        decodeByteBufferToCharacterBuffer(false);
> +                    }
> +                    if (next == '\\') {
> +                        request.consume();
> +                        next = request.nextChar();
> +                        if (!isQuotedSpecial(next)) {
> +                            throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS,
> +                                    "Invalid escaped character in quote: '"
> +                                            + next + "'");
> +                        }
> +                    }
> +                    // TODO: nextChar does not report accurate chars so safe to
> +                    // cast to byte
> +                    buffer.put((byte) next);
> +                    request.consume();
> +                    next = request.nextChar();
> +                }
> +                completeDecoding();
> +                final String result = charBuffer.toString();
> +                return result;
> +
> +            } catch (IllegalStateException e) {
> +                throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding", e);
> +            }
> +        }
> +
> +        private void completeDecoding() throws DecodingException {
> +            decodeByteBufferToCharacterBuffer(true);
> +            flush();
> +            charBuffer.flip();
> +        }
> +
> +        private void flush() throws DecodingException {
> +            final CoderResult coderResult = decoder.flush(charBuffer);
> +            if (coderResult.isOverflow()) {
> +                upsizeCharBuffer();
> +                flush();
> +            } else if (coderResult.isError()) {
> +                throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding");
> +            }
> +        }
> +
> +        /**
> +         * Decodes contents of the byte buffer to the character buffer. The
> +         * character buffer will be replaced by a larger one if required.
> +         *
> +         * @param endOfInput
> +         *            is the input ended
> +         */
> +        private CoderResult decodeByteBufferToCharacterBuffer(
> +                final boolean endOfInput) throws DecodingException {
> +            buffer.flip();
> +            return decodeMoreBytesToCharacterBuffer(endOfInput);
> +        }
> +
> +        private CoderResult decodeMoreBytesToCharacterBuffer(
> +                final boolean endOfInput) throws DecodingException {
> +            final CoderResult coderResult = decoder.decode(buffer, charBuffer,
> +                    endOfInput);
> +            if (coderResult.isOverflow()) {
> +                upsizeCharBuffer();
> +                return decodeMoreBytesToCharacterBuffer(endOfInput);
> +            } else if (coderResult.isError()) {
> +                throw new DecodingException(HumanReadableText.BAD_IO_ENCODING, "Bad character encoding");
> +            } else if (coderResult.isUnderflow()) {
> +                buffer.clear();
> +            }
> +            return coderResult;
> +        }
> +
> +        /**
> +         * Increases the size of the character buffer.
> +         */
> +        private void upsizeCharBuffer() {
> +            final int oldCapacity = charBuffer.capacity();
> +            CharBuffer oldBuffer = charBuffer;
> +            charBuffer = CharBuffer.allocate(oldCapacity
> +                    + QUOTED_BUFFER_INITIAL_CAPACITY);
> +            oldBuffer.flip();
> +            charBuffer.put(oldBuffer);
> +        }
> +    }
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/EolInputStream.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/EolInputStream.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/EolInputStream.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/EolInputStream.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,77 @@
> +/****************************************************************
> + * 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.imap.decode.base;
> +
> +import java.io.FileInputStream;
> +import java.io.FilterInputStream;
> +import java.io.IOException;
> +import java.io.InputStream;
> +
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +
> +/**
> + * {@link FileInputStream} which call the eol() method of the {@link ImapRequestLineReader} when the end
> + * of the wrapped {@link InputStream} is reached
> + *
> + *
> + */
> +public class EolInputStream extends FilterInputStream{
> +
> +    private ImapRequestLineReader reader;
> +    private boolean eolCalled = false;
> +
> +    public EolInputStream(ImapRequestLineReader reader, InputStream in) {
> +        super(in);
> +        this.reader = reader;
> +    }
> +
> +    @Override
> +    public int read() throws IOException {
> +        int i = in.read();
> +        eol(i);
> +        return i;
> +    }
> +
> +    @Override
> +    public int read(byte[] b, int off, int len) throws IOException {
> +        int i = in.read(b, off, len);
> +        eol(i);
> +        return i;
> +    }
> +
> +    @Override
> +    public int read(byte[] b) throws IOException {
> +        int i = in.read(b);
> +        eol(i);
> +        return i;
> +    }
> +
> +    private void eol(int i ) throws IOException{
> +        if (i == -1 && eolCalled == false) {
> +            reader.eol();
> +            eolCalled = true;
> +        }
> +    }
> +
> +    @Override
> +    public int available() throws IOException {
> +        return in.available();
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/FixedLengthInputStream.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/FixedLengthInputStream.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/FixedLengthInputStream.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/base/FixedLengthInputStream.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,101 @@
> +/****************************************************************
> + * 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.imap.decode.base;
> +
> +import java.io.FilterInputStream;
> +import java.io.IOException;
> +import java.io.InputStream;
> +
> +/**
> + *
> + * An input stream which reads a fixed number of bytes from the underlying input
> + * stream. Once the number of bytes has been read, the FixedLengthInputStream
> + * will act as thought the end of stream has been reached, even if more bytes
> + * are present in the underlying input stream.
> + */
> +public class FixedLengthInputStream extends FilterInputStream {
> +    private long pos = 0;
> +
> +    private long length;
> +
> +    public FixedLengthInputStream(InputStream in, long length) {
> +        super(in);
> +        this.length = length;
> +    }
> +
> +    public int read() throws IOException {
> +        if (pos >= length) {
> +            return -1;
> +        }
> +        pos++;
> +        return super.read();
> +    }
> +
> +    public int read(byte b[]) throws IOException {
> +
> +        return read(b, 0, b.length);
> +    }
> +
> +    public int read(byte b[], int off, int len) throws IOException {
> +
> +
> +        if (pos >= length) {
> +            return -1;
> +        }
> +
> +        if (pos + len >= length) {
> +            int readLimit = (int) length - (int) pos;
> +            pos = length;
> +
> +            return super.read(b, off, readLimit);
> +        }
> +
> +
> +        int i =  super.read(b, off, len);
> +        pos += i;
> +        return i;
> +
> +    }
> +
> +    public long skip(long n) throws IOException {
> +        throw new IOException("Not implemented");
> +        // return super.skip( n );
> +    }
> +
> +    public int available() throws IOException {
> +        return (int) (length - pos);
> +    }
> +
> +    public void close() throws IOException {
> +        // Don't do anything to the underlying stream.
> +    }
> +
> +    public void mark(int readlimit) {
> +        // Don't do anything.
> +    }
> +
> +    public synchronized void reset() throws IOException {
> +        throw new IOException("mark not supported");
> +    }
> +
> +    public boolean markSupported() {
> +        return false;
> +    }
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/main/DefaultImapDecoder.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/main/DefaultImapDecoder.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/main/DefaultImapDecoder.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/main/DefaultImapDecoder.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,123 @@
> +/****************************************************************
> + * 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.imap.decode.main;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.api.ImapSessionState;
> +import org.apache.james.imap.api.display.HumanReadableText;
> +import org.apache.james.imap.api.process.ImapSession;
> +import org.apache.james.imap.decode.ImapCommandParser;
> +import org.apache.james.imap.decode.ImapCommandParserFactory;
> +import org.apache.james.imap.decode.ImapDecoder;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + * {@link ImapDecoder} implementation which parse the data via lookup the right {@link ImapCommandParser} via an {@link ImapCommandParserFactory}. The
> + * response will get generated via the {@link ImapMessageFactory}.
> + *
> + */
> +public class DefaultImapDecoder implements ImapDecoder {
> +
> +    private final ImapMessageFactory messageFactory;
> +
> +    private final ImapCommandParserFactory imapCommands;
> +
> +    public DefaultImapDecoder(final ImapMessageFactory messageFactory,
> +            final ImapCommandParserFactory imapCommands) {
> +        this.messageFactory = messageFactory;
> +        this.imapCommands = imapCommands;
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.ImapDecoder#decode(org.apache.james.imap.decode.ImapRequestLineReader, org.apache.james.imap.api.process.ImapSession)
> +     */
> +    public ImapMessage decode(ImapRequestLineReader request, ImapSession session) {
> +        ImapMessage message;
> +        final Log logger = session.getLog();
> +
> +        try {
> +            final String tag = AbstractImapCommandParser.tag(request);
> +            message = decodeCommandTagged(request, logger, tag, session);
> +        } catch (DecodingException e) {
> +            logger.debug("Cannot parse tag", e);
> +
> +            // When the tag cannot be read, there is something seriously wrong.
> +            // It is probably not possible to recover
> +            // and (since this may indicate an attack) wiser not to try
> +            message = messageFactory.bye(HumanReadableText.ILLEGAL_TAG);
> +            session.logout();
> +        }
> +        return message;
> +    }
> +
> +
> +    private ImapMessage decodeCommandTagged(
> +            final ImapRequestLineReader request, final Log logger,
> +            final String tag, final ImapSession session) {
> +        ImapMessage message;
> +        if (logger.isDebugEnabled()) {
> +            logger.debug("Got <tag>: " + tag);
> +        }
> +        try {
> +            final String commandName = AbstractImapCommandParser.atom(request);
> +            message = decodeCommandNamed(request, tag, commandName, logger,
> +                    session);
> +        } catch (DecodingException e) {
> +            logger.debug("Error during initial request parsing", e);
> +            message = unknownCommand(tag, session);
> +        }
> +        return message;
> +    }
> +
> +    private ImapMessage unknownCommand(final String tag,
> +            final ImapSession session) {
> +        ImapMessage message;
> +        if (session.getState() == ImapSessionState.NON_AUTHENTICATED) {
> +            message = messageFactory
> +                    .bye(HumanReadableText.BYE_UNKNOWN_COMMAND);
> +            session.logout();
> +        } else {
> +            message = messageFactory.taggedBad(tag, null,
> +                    HumanReadableText.UNKNOWN_COMMAND);
> +        }
> +        return message;
> +    }
> +
> +    private ImapMessage decodeCommandNamed(final ImapRequestLineReader request,
> +            final String tag, String commandName, final Log logger,
> +            final ImapSession session) {
> +        ImapMessage message;
> +        if (logger.isDebugEnabled()) {
> +            logger.debug("Got <command>: " + commandName);
> +        }
> +        final ImapCommandParser command = imapCommands.getParser(commandName);
> +        if (command == null) {
> +            logger.info("Missing command implementation.");
> +            message = unknownCommand(tag, session);
> +        } else {
> +            message = command.parse(request, tag, logger);
> +        }
> +        return message;
> +    }
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractUidCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractUidCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractUidCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractUidCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,51 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +abstract class AbstractUidCommandParser extends AbstractImapCommandParser {
> +
> +    public AbstractUidCommandParser(final ImapCommand command) {
> +       super(command);
> +    }
> +
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        final ImapMessage result = decode(command, request, tag, false, logger);
> +        return result;
> +    }
> +
> +    public ImapMessage decode(ImapRequestLineReader request, String tag,
> +            boolean useUids, Log logger) throws DecodingException {
> +        final ImapCommand command = getCommand();
> +        final ImapMessage result = decode(command, request, tag, useUids, logger);
> +        return result;
> +    }
> +
> +    protected abstract ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, boolean useUids, Log logger)
> +            throws DecodingException;
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AppendCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AppendCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AppendCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AppendCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,98 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import java.util.Date;
> +
> +import javax.mail.Flags;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +import org.apache.james.imap.decode.base.EolInputStream;
> +
> +/**
> + * Parses APPEND command
> + *
> + */
> +public class AppendCommandParser extends AbstractImapCommandParser {
> +
> +    public AppendCommandParser() {
> +       super(ImapCommand.authenticatedStateCommand(ImapConstants.APPEND_COMMAND_NAME));
> +    }
> +
> +    /**
> +     * If the next character in the request is a '(', tries to read a
> +     * "flag_list" argument from the request. If not, returns a MessageFlags
> +     * with no flags set.
> +     */
> +    public Flags optionalAppendFlags(ImapRequestLineReader request)
> +            throws DecodingException {
> +        char next = request.nextWordChar();
> +        if (next == '(') {
> +            return flagList(request);
> +        } else {
> +            return null;
> +        }
> +    }
> +
> +    /**
> +     * If the next character in the request is a '"', tries to read a DateTime
> +     * argument. If not, returns null.
> +     */
> +    public Date optionalDateTime(ImapRequestLineReader request)
> +            throws DecodingException {
> +        char next = request.nextWordChar();
> +        if (next == '"') {
> +            return dateTime(request);
> +        } else {
> +            return null;
> +        }
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        String mailboxName = mailbox(request);
> +        Flags flags = optionalAppendFlags(request);
> +        if (flags == null) {
> +            flags = new Flags();
> +        }
> +        Date datetime = optionalDateTime(request);
> +        if (datetime == null) {
> +            datetime = new Date();
> +        }
> +        request.nextWordChar();
> +
> +        // Use a EolInputStream so it will call eol when the message was read
> +        final EolInputStream message = new EolInputStream(request, consumeLiteral(request));
> +        final ImapMessageFactory factory = getMessageFactory();
> +        final ImapMessage result = factory.createAppendMessage(command,
> +                mailboxName, flags, datetime, message, tag);
> +        return result;
> +    }
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AuthenticateCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AuthenticateCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AuthenticateCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AuthenticateCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,55 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + *
> + * Parses AUTHENTICATE commands
> + *
> + */
> +public class AuthenticateCommandParser extends AbstractImapCommandParser {
> +
> +    public AuthenticateCommandParser() {
> +       super(ImapCommand.nonAuthenticatedStateCommand(ImapConstants.AUTHENTICATE_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        String authType = astring(request);
> +        endLine(request);
> +        final ImapMessageFactory factory = getMessageFactory();
> +        final ImapMessage result = factory.createAuthenticateMessage(command,
> +                authType, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CapabilityCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CapabilityCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CapabilityCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CapabilityCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,53 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + * Parses CAPABILITY commands
> + *
> + */
> +public class CapabilityCommandParser extends AbstractImapCommandParser {
> +
> +    public CapabilityCommandParser() {
> +       super(ImapCommand.anyStateCommand(ImapConstants.CAPABILITY_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        endLine(request);
> +        final ImapMessageFactory factory = getMessageFactory();
> +        final ImapMessage result = factory
> +                .createCapabilityMessage(command, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CheckCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CheckCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CheckCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CheckCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,51 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + * Parses CHECK commands
> + *
> + */
> +public class CheckCommandParser extends AbstractImapCommandParser {
> +
> +    public CheckCommandParser() {
> +        super(ImapCommand.selectedStateCommand(ImapConstants.CHECK_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        endLine(request);
> +        final ImapMessage result = getMessageFactory().createCheckMessage(
> +                command, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CloseCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CloseCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CloseCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CloseCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,53 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + *
> + *  Parse CLOSE commands
> + *
> + */
> +class CloseCommandParser extends AbstractImapCommandParser  {
> +
> +    public CloseCommandParser() {
> +       super(ImapCommand.selectedStateCommand(ImapConstants.CLOSE_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        endLine(request);
> +        final ImapMessageFactory factory = getMessageFactory();
> +        final ImapMessage result = factory.createCloseMessage(command, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,54 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.api.message.IdRange;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +
> +/**
> + * Parse COPY commands
> + *
> + */
> +public class CopyCommandParser extends AbstractUidCommandParser {
> +
> +    public CopyCommandParser() {
> +        super(ImapCommand.selectedStateCommand(ImapConstants.COPY_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.parser.AbstractUidCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, boolean, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, boolean useUids, Log logger)
> +            throws DecodingException {
> +        IdRange[] idSet = parseIdRange(request);
> +        String mailboxName = mailbox(request);
> +        endLine(request);
> +        final ImapMessage result = getMessageFactory().createCopyMessage(
> +                command, idSet, mailboxName, useUids, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CreateCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CreateCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CreateCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CreateCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,54 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + * Parse CREATE commands
> + *
> + */
> +public class CreateCommandParser extends AbstractImapCommandParser  {
> +
> +    public CreateCommandParser() {
> +        super(ImapCommand.authenticatedStateCommand(ImapConstants.CREATE_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        String mailboxName = mailbox(request);
> +        endLine(request);
> +        final ImapMessageFactory factory = getMessageFactory();
> +        final ImapMessage result = factory.createCreateMessage(command,
> +                mailboxName, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/DeleteCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/DeleteCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/DeleteCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/DeleteCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,54 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + * Parse DELETE commands
> + *
> + */
> +public class DeleteCommandParser extends AbstractImapCommandParser {
> +
> +    public DeleteCommandParser() {
> +        super(ImapCommand.authenticatedStateCommand(ImapConstants.DELETE_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        String mailboxName = mailbox(request);
> +        endLine(request);
> +        final ImapMessageFactory factory = getMessageFactory();
> +        final ImapMessage result = factory.createDeleteMessage(command,
> +                mailboxName, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,52 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + * Parse EXAMINE commands
> + *
> + */
> +public class ExamineCommandParser extends AbstractImapCommandParser {
> +
> +    public ExamineCommandParser() {
> +        super(ImapCommand.authenticatedStateCommand(ImapConstants.EXAMINE_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        final String mailboxName = mailbox(request);
> +        endLine(request);
> +        final ImapMessage result = getMessageFactory().createExamineMessage(
> +                command, mailboxName, tag);
> +        return result;
> +    }
> +
> +}
>
> Added: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java
> URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java?rev=990364&view=auto
> ==============================================================================
> --- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java (added)
> +++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java Sat Aug 28 13:55:56 2010
> @@ -0,0 +1,52 @@
> +/****************************************************************
> + * 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.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapMessageFactory;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + * Parse EXPUNGE commands
> + *
> + */
> +public class ExpungeCommandParser extends AbstractImapCommandParser {
> +
> +    public ExpungeCommandParser() {
> +        super(ImapCommand.selectedStateCommand(ImapConstants.EXPUNGE_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand, org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws DecodingException {
> +        endLine(request);
> +        final ImapMessageFactory factory = getMessageFactory();
> +        final ImapMessage result = factory.createExpungeMessage(command, tag);
> +        return result;
> +    }
> +
> +}
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
> For additional commands, e-mail: server-dev-help@james.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org