/*************************************************************************** * 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.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Response { public static final int RESPONSE_STATUS = 0; public static final int RESPONSE_COLLECTION_DATA = 1; public static final int RESPONSE_ITEM_DATA = 2; public static final int RESPONSE_CONTINUATION = 3; public static Response parse(CharSequence input) throws ProtocolException { // System.err.println( "parse: " + input ); Matcher matcher = mResponsePattern.matcher(input); // Is this a valid response? if (matcher.matches()) { Response result = new Response(input.toString()); // what kind of? (untagged) if (matcher.group(2) != null) { // test for resp-cond (OK/BAD/NO) Matcher responseCode = mStatusResponsePattern.matcher(matcher.group(5)); if (responseCode.matches()) { result.mResponseType = RESPONSE_STATUS; result.mResponseSubType = responseCode.group(1); // do we have a responseCode? if (responseCode.group(3) != null) { // TODO // result.mResponseTextCode = // ResponseTextCodeParser.parse( responseCode.group( 3 ) // ); result.mResponseTextCode = responseCode.group(3); } // set reponse message result.mResponseMessage = responseCode.group(4); return result; } // test for collection data Matcher collectionData = mCollectionDataPattern.matcher(matcher.group(5)); if (collectionData.matches()) { result.mResponseType = RESPONSE_COLLECTION_DATA; result.mEntityId = Long.parseLong(collectionData.group(1)); result.mParentId = Long.parseLong(collectionData.group(2)); // set reponse message result.mResponseMessage = collectionData.group(3); return result; } // test for message-data (EXPUNGE|FECTH) Matcher itemData = mItemDataPattern.matcher(matcher.group(5)); if (itemData.matches()) { result.mResponseType = RESPONSE_ITEM_DATA; result.mEntityId = Long.parseLong(itemData.group(1)); result.mResponseSubType = itemData.group(2); result.mResponseMessage = itemData.group(3); return result; } // Not any of the above subtypes throw new ProtocolException("Unknown subytpe : " + result.getSource()); } // what kind of? (tagged) if (matcher.group(3) != null) { result.mTag = matcher.group(3); // test for resp-cond (OK/BAD/NO) Matcher responseCode = mStatusResponsePattern.matcher(matcher.group(5)); if (responseCode.matches()) { result.mResponseType = RESPONSE_STATUS; result.mResponseSubType = responseCode.group(1); // do we have a responseCode? if (responseCode.group(3) != null) { // TODO // result.mResponseTextCode = // ResponseTextCodeParser.parse( respCode.group( 3 ) ); result.mResponseTextCode = responseCode.group(3); } // set reponse text result.mResponseMessage = responseCode.group(4); return result; } // Not any of the above subtypes throw new ProtocolException("Unknown subytpe :" + result.getSource()); } // what kind of? (continuation) if (matcher.group(4) != null) { result.mResponseType = RESPONSE_CONTINUATION; Matcher responseContinuation = mResponseContinuationPattern.matcher(matcher.group(5)); if (responseContinuation.matches()) { // do we have a responseCode? if (responseContinuation.group(2) != null) { // TODO // result.mResponseTextCode = // ResponseTextCodeParser.parse( // responseContinuation.group( 2 ) ); result.mResponseTextCode = responseContinuation.group(2); } // set reponse text result.mResponseMessage = responseContinuation.group(3); return result; } } } throw new ProtocolException("Not a valid Akonadi response : " + input); } public boolean isTagged() { return mTag != null; } public String getTag() { return mTag; } public boolean isOK() { return mResponseSubType.equals("OK"); } public boolean isNO() { return mResponseSubType.equals("NO"); } public boolean isBAD() { return mResponseSubType.equals("BAD"); } public int getResponseType() { return mResponseType; } public String getResponseSubType() { return mResponseSubType; } public String getResponseMessage() { return mResponseMessage; } public String getResponseTextCode() { return mResponseTextCode; } public long getEntityId() { return mEntityId; } public long getParentId() { return mParentId; } public String getSource() { StringBuffer cleanedUp = new StringBuffer(mSource.length()); mLiteralMatcher.reset(mSource); while (mLiteralMatcher.find()) { mLiteralMatcher.appendReplacement(cleanedUp, getData(mLiteralMatcher.group()).toString()); } mLiteralMatcher.appendTail(cleanedUp); return cleanedUp.toString(); } public CharSequence getData(CharSequence data) { if (data.length() == 0) return data; mLiteralMatcher.reset(data); if (mLiteralMatcher.matches()) { return getLiteral(Integer.parseInt(mLiteralMatcher.group(1))); } else { // remove "" if (data.charAt(0) == '"') { return data.subSequence(1, data.length() - 1); } else { return data; } } } public CharSequence getLiteral(int index) { return mLiterals.get(index); } protected Response(String source) { mSource = source; mEntityId = -1; mParentId = -1; } protected void addLiteral(CharSequence literal) { if (mLiterals == null) { mLiterals = new LinkedList<CharSequence>(); } mLiterals.add(literal); } protected void appendResponseText(String restResponse) { mSource += restResponse; mResponseMessage += restResponse; } protected Matcher literalMatcher() { return mLiteralMatcher; } protected String mSource; protected String mTag; protected int mResponseType; protected String mResponseSubType; protected String mResponseMessage; protected String mResponseTextCode; protected long mEntityId; protected long mParentId; protected List<CharSequence> mLiterals; // Pattern to classify the response in tagged/untagged/continuation // and to access the text of the reponse without the trailing CRLF private static final Pattern mResponsePattern = Pattern.compile("^((\\*)" + // group // 2 // is // untagged "|([0-9a-zA-Z]+)" + // group 3 is the tag "|(\\+)) " + // group 4 is continuation "([^\r\n]*)\r?\n?"); // group 5 is the rest of the response without // a optional CRLF // Pattern to classify a status reponse. private static final Pattern mStatusResponsePattern = Pattern.compile("^(OK|BAD|NO) " + // group // 1 // is // the // status // type "(\\[(\\w+[^\\]]+)\\])?" + // group 3 is an optional text // code " ?([^\r\n]*)"); // group 4 is the message // Pattern to classify a collection data response. private static final Pattern mCollectionDataPattern = Pattern.compile("^(\\d+)" + // group1 // contains // the // collection // id " (\\d+)" + // group2 contains the collection parent id " ?([^\r\n]*)"); // group3 contains the data // Pattern to classify a message data response. private static final Pattern mItemDataPattern = Pattern.compile("^(\\d+) " + // group1 // contains // the // item // id "(EXPUNGE|FETCH)" + // group2 contains the command " ?([^\r\n]*)"); // group3 contains the data // Pattern to classify a continuation response. private static final Pattern mResponseContinuationPattern = Pattern.compile("^(\\[(\\w+[^\\]]+)\\] )?" + // group2 // contains // optional // text code "([^\r\n]*)"); // group3 contains the message private static final Pattern mLiteralPattern = Pattern.compile("^\\{(\\d+)\\}$"); private static final Matcher mLiteralMatcher = mLiteralPattern.matcher(""); }