@SuppressWarnings("unchecked")
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
buffer.markReaderIndex();
boolean retry = false;
ImapRequestLineReader reader;
// check if we failed before and if we already know how much data we
// need to sucess next run
Map<String, Object> attachment = (Map<String, Object>) ctx.getAttachment();
int size = -1;
if (attachment.containsKey(NEEDED_DATA)) {
retry = true;
size = (Integer) attachment.get(NEEDED_DATA);
// now see if the buffer hold enough data to process.
if (size != NettyImapRequestLineReader.NotEnoughDataException.UNKNOWN_SIZE && size > buffer.readableBytes()) {
// check if we have a inMemorySize limit and if so if the
// expected size will fit into it
if (inMemorySizeLimit > 0 && inMemorySizeLimit < size) {
// ok seems like it will not fit in the memory limit so we
// need to store it in a temporary file
final File f;
int written;
OutputStream out;
// check if we have created a temporary file already or if
// we need to create a new one
if (attachment.containsKey(STORED_DATA)) {
f = (File) attachment.get(STORED_DATA);
written = (Integer) attachment.get(WRITTEN_DATA);
out = (OutputStream) attachment.get(OUTPUT_STREAM);
} else {
f = File.createTempFile("imap-literal", ".tmp");
attachment.put(STORED_DATA, f);
written = 0;
attachment.put(WRITTEN_DATA, written);
out = new FileOutputStream(f, true);
attachment.put(OUTPUT_STREAM, out);
}
try {
int amount = Math.min(buffer.readableBytes(), size - written);
buffer.readBytes(out, amount);
written += amount;
} catch (Exception e) {
IOUtils.closeQuietly(out);
throw e;
}
// Check if all needed data was streamed to the file.
if (written == size) {
IOUtils.closeQuietly(out);
reader = new NettyStreamImapRequestLineReader(channel, new FileInputStream(f) {
/**
* Delete the File on close too
*/
@Override
public void close() throws IOException {
super.close();
if (!f.delete()) {
throw new IOException("Unable to delete file " + f);
}
}
}, retry);
} else {
attachment.put(WRITTEN_DATA, written);
return null;
}
} else {
buffer.resetReaderIndex();
return null;
}
} else {
reader = new NettyImapRequestLineReader(channel, buffer, retry, literalSizeLimit);
}
} else {
reader = new NettyImapRequestLineReader(channel, buffer, retry, literalSizeLimit);
}
ImapSession session = (ImapSession) attributes.get(channel);
// check if the session was removed before to prevent a harmless NPE. See JAMES-1312
// Also check if the session was logged out if so there is not need to try to decode it. See JAMES-1341
if (session != null && session.getState() != ImapSessionState.LOGOUT) {
try {
ImapMessage message = decoder.decode(reader, session);
// if size is != -1 the case was a literal. if thats the case we
// should not consume the line
// See JAMES-1199
if (size == -1) {
reader.consumeLine();
}
// Code portion commented further to JAMES-1436.
// TODO Remove if no negative feedback on JAMES-1436.
// ChannelHandler handler = (ChannelHandler) attachment.remove(FRAMER);