/**
*
*/
package fr.cedrik.email.fs.mbox;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.lang3.ArrayUtils;
import fr.cedrik.email.fs.BaseZipWriter;
import fr.cedrik.email.spi.Message;
import fr.cedrik.util.AppleDouble;
import fr.cedrik.util.DateUtils;
/**
* @author Cédrik LIME
*/
public class MBoxrdZipWriter extends BaseZipWriter {
public static final String MAILBOX_SUFFIX = ".mbox";//fr.cedrik.inotes.fs.mbox.MBoxrd.EXTENSION_MBOXRD;//$NON-NLS-1$
protected long latestExportedMessageDate = -1; // per folder
public MBoxrdZipWriter(ZipOutputStream out, String baseName) {
super(out, baseName);
}
@Override
public void openFolder(String folderChainStr) throws IOException {
newZipEntry(folderChainStr, null);
}
@Override
public void openFile(String folderChainStr, Message message) throws IOException {
// noop
}
@Override
protected String computeZipMailFileName(String folderChainStr, Message message) {
return baseName + folderChainStr + MAILBOX_SUFFIX;
}
@Override
protected void writeMIME(Writer mbox, Message message, Iterator<String> mime) throws IOException {
writeFromLine(mbox, message);
while (mime.hasNext()) {
String line = mime.next();
Matcher from_ = FROM_.matcher(line);
if (from_.find()) {
logger.trace("Escaping {}", from_.group());
mbox.write('>');
}
mbox.append(line).append(newLine());
}
mbox.write(newLine());
if (message != null && message.getDate() != null) {
latestExportedMessageDate = Math.max(latestExportedMessageDate, message.getDate().getTime());
}
}
@Override
public void closeFile(Message message) throws IOException {
// noop
}
@Override
public void closeFolder() throws IOException {
if (latestExportedMessageDate > 0) {
currentEntry.setTime(latestExportedMessageDate);
}
ZipEntry entry = currentEntry; // necessary since currentEntry is null'ed in close()
super.closeZipEntry();
setTEXTtype(outStream, entry);
}
private static final Pattern FROM_ = Pattern.compile("^>*From ");//$NON-NLS-1$
protected void writeFromLine(Writer mbox, Message message) throws IOException {
// date should be UTC, but tests show there is no need to convert it
mbox.append("From MAILER-DAEMON ").append(DateUtils.MBOX_DATE_TIME_FORMAT.format(message.getDate())).append(newLine());
}
/**
* @return Outlook-compliant new-line char
*/
@Override
protected String newLine() {
return "\n";//$NON-NLS-1$
}
/**
* Outlook 2011 is an old Carbon app that requires its data file to have a 'TEXT' file type; creator is not used.
* @param outZip
* @param name
* @throws IOException
*/
protected void setTEXTtype(ZipOutputStream outZip, ZipEntry entry) throws IOException {
ZipEntry adEntry = new ZipEntry(AppleDouble.getAppleDoubleFileName(entry.getName()));
adEntry.setTime(entry.getTime());
outZip.putNextEntry(adEntry);
outZip.write(APPLE_DOUBLE__TEXT_TYPE);
outZip.closeEntry();
}
// public for JUnit tests only
public static final byte[] APPLE_DOUBLE__TEXT_TYPE;
static {
byte[] RESOURCE_FORK_EMPTY = ArrayUtils.EMPTY_BYTE_ARRAY;
byte[] FINDER_INFO_TEXT = new byte[32];
FINDER_INFO_TEXT[0] = 'T';
FINDER_INFO_TEXT[1] = 'E';
FINDER_INFO_TEXT[2] = 'X';
FINDER_INFO_TEXT[3] = 'T';
AppleDouble.EntryDescriptor[] adEntryDescriptors = new AppleDouble.EntryDescriptor[] {
new AppleDouble.EntryDescriptor(AppleDouble.EntryDescriptor.FINDER_INFO, FINDER_INFO_TEXT),
new AppleDouble.EntryDescriptor(AppleDouble.EntryDescriptor.RESOURCE_FORK, RESOURCE_FORK_EMPTY)
};
APPLE_DOUBLE__TEXT_TYPE = new AppleDouble(adEntryDescriptors).getBytes();
}
}