📄 commandparser.java
字号:
/*********************************************************************** * Copyright (c) 2000-2004 The Apache Software Foundation. * * All rights reserved. * * ------------------------------------------------------------------- * * 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.imapserver.commands;import org.apache.james.imapserver.ProtocolException;import org.apache.james.imapserver.ImapRequestLineReader;import org.apache.james.imapserver.ImapConstants;import org.apache.james.imapserver.store.MessageFlags;import org.apache.james.util.Assert;import java.util.Date;import java.util.TimeZone;import java.util.List;import java.util.ArrayList;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.text.ParseException;/** * * * @version $Revision: 1.5.2.3 $ */public class CommandParser{ private static final char[] EMPTY_CHAR_ARRAY = new char[0]; /** * Reads an argument of type "atom" from the request. */ public String atom( ImapRequestLineReader request ) throws ProtocolException { return consumeWord( request, new ATOM_CHARValidator() ); } /** * Reads a command "tag" from the request. */ public String tag(ImapRequestLineReader request) throws ProtocolException { CharacterValidator validator = new TagCharValidator(); return consumeWord( request, validator ); } /** * Reads an argument of type "astring" from the request. */ public String astring(ImapRequestLineReader request) throws ProtocolException { char next = request.nextWordChar(); switch ( next ) { case '"': return consumeQuoted( request ); case '{': return consumeLiteral( request ); default: return atom( request ); } } /** * Reads an argument of type "nstring" from the request. */ public String nstring( ImapRequestLineReader request ) throws ProtocolException { char next = request.nextWordChar(); switch ( next ) { case '"': return consumeQuoted( request ); case '{': return consumeLiteral( request ); default: String value = atom( request ); if ( "NIL".equals( value ) ) { return null; } else { throw new ProtocolException( "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 ProtocolException { String mailbox = astring( request ); if ( mailbox.equalsIgnoreCase( ImapConstants.INBOX_NAME ) ) { return ImapConstants.INBOX_NAME; } else { return mailbox; } } /** * Reads a "date-time" argument from the request. * TODO handle timezones properly */ public Date dateTime( ImapRequestLineReader request ) throws ProtocolException { char next = request.nextWordChar(); String dateString; if ( next == '"' ) { dateString = consumeQuoted( request ); } else { throw new ProtocolException( "DateTime values must be quoted." ); } DateFormat dateFormat = new SimpleDateFormat( "dd-MMM-yyyy hh:mm:ss zzzz" ); try { return dateFormat.parse( dateString ); } catch ( ParseException e ) { throw new ProtocolException( "Invalid date format." ); } } /** * Reads a "date" argument from the request. * TODO handle timezones properly */ public Date date( ImapRequestLineReader request ) throws ProtocolException { char next = request.nextWordChar(); String dateString; if ( next == '"' ) { dateString = consumeQuoted( request ); } else { dateString = atom( request ); } DateFormat dateFormat = new SimpleDateFormat( "dd-MMM-yyyy" ); try { return dateFormat.parse( dateString ); } catch ( ParseException e ) { throw new ProtocolException( "Invalid date format." ); } } /** * 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 String consumeWord( ImapRequestLineReader request, CharacterValidator validator ) throws ProtocolException { StringBuffer atom = new StringBuffer(); char next = request.nextWordChar(); while( ! isWhitespace( next ) ) { if ( validator.isValid( next ) ) { atom.append( next ); request.consume(); } else { throw new ProtocolException( "Invalid character: '" + next + "'" ); } next = request.nextChar(); } return atom.toString(); } private 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. */ protected String consumeLiteral( ImapRequestLineReader request ) throws ProtocolException { // 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(); } int size = Integer.parseInt( digits.toString() ); byte[] buffer = new byte[size]; request.read( buffer ); return new String( buffer ); } /** * Consumes a CRLF from the request. * TODO we're being liberal, the spec insists on \r\n for new lines. * @param request * @throws ProtocolException */ private void consumeCRLF( ImapRequestLineReader request ) throws ProtocolException { 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 ProtocolException { char consumed = request.consume(); if ( consumed != expected ) { throw new ProtocolException( "Expected:'" + expected + "' found:'" + consumed + "'" ); } } /** * Reads a quoted string value from the request. */ protected String consumeQuoted( ImapRequestLineReader request ) throws ProtocolException { // The 1st character must be '"' consumeChar(request, '"' ); StringBuffer quoted = new StringBuffer(); char next = request.nextChar(); while( next != '"' ) { if ( next == '\\' ) { request.consume(); next = request.nextChar(); if ( ! isQuotedSpecial( next ) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -