    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.net.imap;
    019
    020    import java.io.IOException;
    021    import java.util.regex.Matcher;
    022    import java.util.regex.Pattern;
    023
    024    import org.apache.commons.net.MalformedServerReplyException;
    025
    026    /**
    027     * IMAPReply stores IMAP reply code constants.
    028     */
    029
    030    public final class IMAPReply
    031    {
    032        /** The reply code indicating success of an operation. */
    033        public static final int OK = 0;
    034
    035        /** The reply code indicating failure of an operation. */
    036        public static final int NO = 1;
    037
    038        /** The reply code indicating command rejection. */
    039        public static final int BAD = 2;
    040
    041        /** The reply code indicating command continuation. */
    042        public static final int CONT = 3;
    043
    044        /** The IMAP reply String indicating success of an operation. */
    045        private static final String IMAP_OK = "OK";
    046
    047        /** The IMAP reply String indicating failure of an operation. */
    048        private static final String IMAP_NO = "NO";
    049
    050        /** The IMAP reply String indicating command rejection. */
    051        private static final String IMAP_BAD = "BAD";
    052
    053        // Start of line for untagged replies
    054        private static final String IMAP_UNTAGGED_PREFIX = "* ";
    055
    056        // Start of line for continuation replies
    057        private static final String IMAP_CONTINUATION_PREFIX = "+";
    058
    059        // Cannot be instantiated.
    060        private IMAPReply()
    061        {}
    062
    063        /**
    064         * Checks if the reply line is untagged - e.g. "* OK ..."
    065         * @param line to be checked
    066         * @return {@code true} if the line is untagged
    067         */
    068        public static boolean isUntagged(String line) {
    069            return line.startsWith(IMAP_UNTAGGED_PREFIX);
    070        }
    071
    072        /**
    073         * Checks if the reply line is a continuation, i.e. starts with "+"
    074         * @param line the line to be checked
    075         * @return {@code true} if the line is untagged
    076         */
    077        public static boolean isContinuation(String line) {
    078            return line.startsWith(IMAP_CONTINUATION_PREFIX);
    079        }
    080
    081        private static final String TAGGED_RESPONSE = "^\\w+ (\\S+).*"; // TODO perhaps be less strict on tag match?
    082        // tag cannot contain: + ( ) { SP CTL % * " \ ]
    083        private static final Pattern TAGGED_PATTERN = Pattern.compile(TAGGED_RESPONSE);
    084
    085        /**
    086         * Intepret the String reply code - OK, NO, BAD - in a tagged response as a integer.
    087         *
    088         * @param line the tagged line to be checked
    089         * @return {@link #OK} or {@link #NO} or {@link #BAD}
    090         * @throws IOException if the input has an unexpected format
    091         */
    092        public static int getReplyCode(String line) throws IOException {
    093            return getReplyCode(line, TAGGED_PATTERN);
    094        }
    095
    096        private static final String UNTAGGED_RESPONSE = "^\\* (\\S+).*";
    097        private static final Pattern UNTAGGED_PATTERN = Pattern.compile(UNTAGGED_RESPONSE);
    098
    099        /**
    100         * Intepret the String reply code - OK, NO, BAD - in an untagged response as a integer.
    101         *
    102         * @param line the untagged line to be checked
    103         * @return {@link #OK} or {@link #NO} or {@link #BAD}
    104         * @throws IOException if the input has an unexpected format
    105         */
    106        public static int getUntaggedReplyCode(String line) throws IOException {
    107            return getReplyCode(line, UNTAGGED_PATTERN);
    108        }
    109
    110        // Helper method to process both tagged and untagged replies.
    111        private static int getReplyCode(String line, Pattern pattern) throws IOException{
    112            if (isContinuation(line)) {
    113                return CONT;
    114            }
    115            Matcher m = pattern.matcher(line);
    116            if (m.matches()) {
    117                String code = m.group(1);
    118                if (code.equals(IMAP_OK)) {
    119                    return OK;
    120                }
    121                if (code.equals(IMAP_BAD)) {
    122                    return BAD;
    123                }
    124                if (code.equals(IMAP_NO)) {
    125                    return NO;
    126                }
    127            }
    128            throw new MalformedServerReplyException(
    129                "Received unexpected IMAP protocol response from server: '" + line + "'.");
    130        }
    131
    132        /**
    133         * Checks whether the reply code indicates success or not
    134         *
    135         * @param replyCode the code to check
    136         * @return {@code true} if the code equals {@link #OK}
    137         */
    138        public static boolean isSuccess(int replyCode) {
    139            return replyCode == OK;
    140        }
    141        /**
    142         * Checks if the reply line is a continuation, i.e. starts with "+"
    143         * @param replyCode the code to be checked
    144         * @return {@code true} if the response was a continuation
    145         */
    146        public static boolean isContinuation(int replyCode) {
    147            return replyCode == CONT;
    148        }
    149
    150    }
    151
    152    /* kate: indent-width 4; replace-tabs on; */