/*************************************************************************** * Copyright (C) 2009 by Kevin Krammer <kevin.krammer@gmx.at> * * * * Based on code from the Ristretto Mail API * * http://freshmeat.net/projects/ristretto/ * * Copyright (C) 2004 by Frederik Dietz <fdietz@users.sourceforge.net> * * Copyright (C) 2004 by Timo Stich <tstich@users.sourceforge.net> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2.1 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ package org.akonadiproject.akonadi; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Iterator; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; public class Command { private String mTag; private String mCommand; private Object[] mParameters; private boolean mLastWasLiteral; private Charset mCharset; public Command(String tag, String command) { this(tag, command, null); } public Command(String tag, String command, Object[] parameters) { this(tag, command, parameters, Charset.forName("ISO-8859-1")); } public Command(String tag, String command, Object[] parameters, Charset charset) { mTag = tag; mCommand = command; mParameters = parameters; mCharset = charset; } public String getTag() { return mTag; } protected void writeToStream(ResponseInputStream in, OutputStream out) throws ProtocolException, IOException { Object arg; out.write(mTag.getBytes("US-ASCII")); out.write(' '); out.write(mCommand.getBytes("US-ASCII")); // write arguments if (mParameters != null) { Iterator<Object> it = Arrays.asList(mParameters).iterator(); while (it.hasNext()) { out.write(' '); arg = it.next(); if (arg instanceof String) { writeString((String) arg, in, out); } else if (arg instanceof String[]) { writeStringArray((String[]) arg, in, out); /* * } else if ( arg instanceof InputStream ) { * writeInputStream( (InputStream) arg, in, out ); */ /* * } else if ( arg instanceof SearchKey ) { writeSearchKey( * (SearchKey) arg, in, out ); */ } else if (arg instanceof byte[]) { writeByteArray(((byte[]) arg), in, out); } else if (arg instanceof char[]) { writeCharArray(((char[]) arg), out); /* * } else if ( arg instanceof Section ) { writeSection( * (Section) arg, in, out ); */ } else { writeCharArray(arg.toString().toCharArray(), out); } } } out.write('\r'); out.write('\n'); out.flush(); } private void writeCharArray(char[] cs, OutputStream out) throws ProtocolException, IOException { for (int i = 0; i < cs.length; ++i) { out.write(cs[i]); } } private void writeByteArray(byte[] bs, ResponseInputStream in, OutputStream out) throws ProtocolException, IOException { out.write('{'); out.write(Integer.toString(bs.length).getBytes(mCharset.name())); out.write('}'); out.write('\r'); out.write('\n'); out.flush(); Response response = in.readResponse(); // TODO: better exception if (response.getResponseType() != Response.RESPONSE_CONTINUATION) throw new ProtocolException(response); out.write(bs); out.flush(); mLastWasLiteral = true; } private void writeStringArray(String[] strings, ResponseInputStream in, OutputStream out) throws ProtocolException, IOException { out.write('('); if (strings.length > 0) { out.write(strings[0].getBytes(mCharset.name())); for (int i = 1; i < strings.length; ++i) { out.write(' '); writeString(strings[i], in, out); } } out.write(')'); mLastWasLiteral = false; } private void writeString(String sequence, ResponseInputStream in, OutputStream out) throws ProtocolException, IOException { // check if the argument is 7-bit, " and \ safe boolean plainSafe = true; boolean quote = sequence.length() == 0; int i = 0; while (i < sequence.length() && plainSafe) { plainSafe &= sequence.charAt(i) < 128; plainSafe &= sequence.charAt(i) != '\"'; plainSafe &= sequence.charAt(i) != '\\'; plainSafe &= sequence.charAt(i) != '\0'; plainSafe &= sequence.charAt(i) != '\r'; plainSafe &= sequence.charAt(i) != '\n'; quote |= sequence.charAt(i) == ' '; quote |= sequence.charAt(i) == '('; quote |= sequence.charAt(i) == ')'; quote |= sequence.charAt(i) == '{'; quote |= sequence.charAt(i) == '%'; quote |= sequence.charAt(i) == '*'; quote |= sequence.charAt(i) == ']'; // quote |= sequence.charAt(i) == '/'; ++i; } // write as literal if not plain safe else just write the bytes if (plainSafe) { if (quote) { out.write('\"'); } out.write(sequence.getBytes(mCharset.name())); if (quote) { out.write('\"'); } mLastWasLiteral = false; } else { writeByteArray(sequence.getBytes(mCharset.name()), in, out); } } @Override public String toString() { return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString(); } }