/**
*
*/
package fr.cedrik.email.pop3.commands;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.mail.MailParseException;
import fr.cedrik.email.MessagesMetaData;
import fr.cedrik.email.pop3.Context;
import fr.cedrik.email.pop3.POP3Command;
import fr.cedrik.email.pop3.ResponseStatus;
import fr.cedrik.email.spi.Message;
import fr.cedrik.util.IteratorChain;
/**
* @author Cédrik LIME
*/
public class TOP extends BasePOP3Command implements POP3Command {
public TOP() {
}
@Override
public Iterator<String> call(Context context) throws IOException {
int requestedMessageNumber = -1;
int requestedLinesNumber = -1;
StringTokenizer tokenizer = new StringTokenizer(context.inputArgs);
if (tokenizer.countTokens() != 2) {
return new IteratorChain<String>(ResponseStatus.NEGATIVE.toString("TOP msg n"));
}
try {
requestedMessageNumber = Integer.parseInt(tokenizer.nextToken());
} catch (NumberFormatException noInput) {
return new IteratorChain<String>(ResponseStatus.NEGATIVE.toString("no such message"));
}
try {
requestedLinesNumber = Integer.parseInt(tokenizer.nextToken());
} catch (NumberFormatException noInput) {
return new IteratorChain<String>(ResponseStatus.NEGATIVE.toString("bad number of lines"));
}
if (requestedLinesNumber < 0) {
return new IteratorChain<String>(ResponseStatus.NEGATIVE.toString("must supply a non-negative number of lines"));
}
MessagesMetaData<?> messages = context.remoteSession.getMessagesMetaData();
if (requestedMessageNumber > messages.entries.size()) {
return new IteratorChain<String>(ResponseStatus.NEGATIVE.toString("no such message, only " + messages.entries.size() + " messages in maildrop"));
}
// TODO may NOT refer to a message marked as deleted
Message message = messages.entries.get(requestedMessageNumber - 1);
List<String> emptyLine = new ArrayList<String>(1);
emptyLine.add("");
if (requestedLinesNumber == 0) {
Iterator<String> mimeHeaders;
try {
mimeHeaders = context.remoteSession.getMessageMIMEHeaders(message);
} catch (MailParseException mpe) {
mimeHeaders = null;
}
if (mimeHeaders == null) {
return new IteratorChain<String>(ResponseStatus.NEGATIVE.toString("unknown error: can not retrieve message headers"));
}
String responseStatus = ResponseStatus.POSITIVE.toString("top " + requestedLinesNumber + " lines of message " + message.getId() + " follows");
return new IteratorChain<String>(responseStatus, mimeHeaders, emptyLine.iterator());
} else {
// Can not simply count the number of lines in the header to finally fetch the full message body,
// as mime headers are slightly different between those (yeah, Notes rocks!)...
// We must therefore manually search for header/body separation and count the lines... :-(
IteratorChain<String> mimeMessage;
try {
mimeMessage = context.remoteSession.getMessageMIME(message);
} catch (MailParseException mpe) {
mimeMessage = null;
}
if (mimeMessage == null) {
return new IteratorChain<String>(ResponseStatus.NEGATIVE.toString("unknown error: can not retrieve message"));
}
List<String> mimeHeaders = new ArrayList<String>(64);
int headerLinesCount = 0;
while (mimeMessage.hasNext()) {
String mimeHeaderLine = mimeMessage.next();
mimeHeaders.add(mimeHeaderLine);
++headerLinesCount;
if (StringUtils.isEmpty(mimeHeaderLine)) {
// end of headers
break;
}
}
mimeMessage.setMaxElementsCap(headerLinesCount + requestedLinesNumber);
String responseStatus = ResponseStatus.POSITIVE.toString("top " + requestedLinesNumber + " lines of message " + message.getId() + " follows");
return new IteratorChain<String>(responseStatus, mimeHeaders.iterator(), mimeMessage, emptyLine.iterator());
}
}
}