[prev in list] [next in list] [prev in thread] [next in thread]
List: james-user
Subject: Re: mboxrd support
From: Philip Tomlinson <phil () ez123 ! co ! nz>
Date: 2006-12-17 1:42:16
Message-ID: 4584A078.7080702 () ez123 ! co ! nz
[Download RAW message or body]
Hi,
I think I've answered my own question and discovered a bug with
MBoxMailRepository and a fix is below.
Line 283
was:
prevMessageStart = ins.getFilePointer() - line.length() ;
should be:
prevMessageStart = ins.getFilePointer() - line.length() - 2;
This is the case because we need to subtract -1 to back up in front of
the character we are looking for and -1 because the readLine doesnt
return the carriage return
Now the preMessageStart points to the F character in the pattern From
.......
and line 413
was:
ins.seek(messageStart -1);
should be:
ins.seek(messageStart );
Given that the messageStart now points at the F character there is no
longer a need to back up one character.
The full file is attached.
Now I can parse Thunderbird mail files without a problem
Rgds,
Phil
> I've been trying to use the MBoxMailRepository to parse a Thunderbird
> mail file.
> It doesnt seem to work propely. (After loading the messages, the
> retrieve operation quite often doesnt return a message for a key).
>
> Is this because the MBoxMailRepository class doesnt support mboxrd?
>
-------------------------
Email: phil@ez123.co.nz
["MBoxMailRepository.java" (text/plain)]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
/* TODO:
*
* 1. Currently, iterating through the message collection does not
* preserve the order in the file. Change this with some form of
* OrderedMap. There is a suitable class in Jakarta Commons
* Collections.
*
* 2. Optimize the remove operation.
*
* 3. Don't load entire message into memory. This would mean computing
* the hash during I/O streaming, rather than loading entire message
* into memory, and using a MimeMessageWrapper with a suitable data
* source. As a strawman, the interface to MessageAction would
* carry the hash, along with a size-limited stream providing the
* message body.
*
* 4. Decide what to do when there are IDENTICAL messages in the file.
* Right now only the last one will ever be processed, due to key
* collissions.
*
* 5. isComplete() - DONE.
*
* 6. Buffered I/O. - Partially done, and optional.
*
*/
package org.apache.james.mailrepository;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.james.core.MailImpl;
import org.apache.james.services.MailRepository;
import org.apache.mailet.Mail;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Matcher;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.NoSuchAlgorithmException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Locale;
import java.util.Properties;
import java.util.Vector;
/**
* Implementation of a MailRepository using UNIX mbox files.
*
* <p>Requires a configuration element in the .conf.xml file of the form:
* <br><repository destinationURL="mbox://<directory>"
* <br> type="MAIL"
* <br></directory> is where the individual mbox files are read from/written \
to
* <br>Type can ONLY be MAIL (SPOOL is NOT supported)
*
* <p>Requires a logger called MailRepository.
*
* <p> Implementation notes:
* <p>
* This class keeps an internal store of the mbox file
* When the internal mbox file is updated (added/deleted)
* then the file will be re-read from disk and then written back.
* This is a bit inefficent but means that the file on disk
* should be correct.
* <p>
* The mbox store is mainly meant to be used as a one-way street.
* Storing new emails is very fast (append to file) whereas reading them (via POP3) \
is
* slower (read from disk and parse).
* Therefore this implementation is best suited to people who wish to use the mbox \
format
* for taking data out of James and into something else (IMAP server or mail list \
displayer)
*
* @version CVS $Revision: 453945 $
*/
public class MBoxMailRepository
extends AbstractLogEnabled
implements MailRepository, Configurable {
static final SimpleDateFormat dy = new SimpleDateFormat("EE MMM dd HH:mm:ss \
yyyy", Locale.US); static final String LOCKEXT = ".lock";
static final String WORKEXT = ".work";
static final int LOCKSLEEPDELAY = 2000; // 2 second back off in the event of a \
problem with the lock file static final int MAXSLEEPTIMES = 100; //
static final long MLISTPRESIZEFACTOR = 10 * 1024; // The hash table will be \
loaded with a initial capacity of filelength/MLISTPRESIZEFACTOR static final long \
DEFAULTMLISTCAPACITY = 20; // Set up a hashtable to have a meaningful default
/**
* Whether line buffering is turned used.
*/
private static boolean BUFFERING = true;
/**
* Whether 'deep debugging' is turned on.
*/
private static final boolean DEEP_DEBUG = true;
/**
* The internal list of the emails
* The key is an adapted MD5 checksum of the mail
*/
private Hashtable mList = null;
/**
* The filename to read & write the mbox from/to
*/
private String mboxFile;
private boolean fifo;
/**
* A callback used when a message is read from the mbox file
*/
public interface MessageAction {
public boolean isComplete(); // *** Not valid until AFTER each call to \
messageAction(...)!
public MimeMessage messageAction(String messageSeparator, String bodyText, \
long messageStart); }
/**
* Convert a MimeMessage into raw text
* @param mc The mime message to convert
* @return A string representation of the mime message
* @throws IOException
* @throws MessagingException
*/
private String getRawMessage(MimeMessage mc) throws IOException, \
MessagingException {
ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
mc.writeTo(rawMessage);
return rawMessage.toString();
}
/**
* Parse a text block as an email and convert it into a mime message
* @param emailBody The headers and body of an email. This will be parsed into a \
mime message and stored
*/
private MimeMessage convertTextToMimeMessage(String emailBody) {
//this.emailBody = emailBody;
MimeMessage mimeMessage = null;
// Parse the mime message as we have the full message now (in string format)
ByteArrayInputStream mb = new ByteArrayInputStream(emailBody.getBytes());
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props);
try {
mimeMessage = new MimeMessage(session, mb);
} catch (MessagingException e) {
getLogger().error("Unable to parse mime message!", e);
}
if (mimeMessage == null && getLogger().isDebugEnabled()) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Mime message is null");
getLogger().debug(logBuffer.toString());
}
/*
String toAddr = null;
try {
// Attempt to read the TO field and see if it errors
toAddr = \
mimeMessage.getRecipients(javax.mail.Message.RecipientType.TO).toString(); } catch \
(Exception e) { // It has errored, so time for plan B
// use the from field I suppose
try {
mimeMessage.setRecipients(javax.mail.Message.RecipientType.TO, \
mimeMessage.getFrom()); if (getLogger().isDebugEnabled()) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Patching To: field for message ")
.append(" with From: field");
getLogger().debug(logBuffer.toString());
}
} catch (MessagingException e1) {
getLogger().error("Unable to set to: field to from: field", e);
}
} */
return mimeMessage;
}
/**
* Generate a hex representation of an MD5 checksum on the emailbody
* @param emailBody
* @return A hex representation of the text
* @throws NoSuchAlgorithmException
*/
private String generateKeyValue(String emailBody) throws NoSuchAlgorithmException \
{ // MD5 the email body for a reilable (ha ha) key
byte[] digArray = \
MessageDigest.getInstance("MD5").digest(emailBody.getBytes()); StringBuffer digest = \
new StringBuffer(); for (int i = 0; i < digArray.length; i++) {
digest.append(Integer.toString(digArray[i], \
Character.MAX_RADIX).toUpperCase(Locale.US)); }
return digest.toString();
}
/**
* Parse the mbox file.
* @param ins The random access file to load. Note that the file may or may not \
start at offset 0 in the file
* @param messAct The action to take when a message is found
*/
private MimeMessage parseMboxFile(RandomAccessFile ins, MessageAction messAct) {
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Start parsing ")
.append(mboxFile);
getLogger().debug(logBuffer.toString());
}
try {
Perl5Compiler sepMatchCompiler = new Perl5Compiler();
Pattern sepMatchPattern = sepMatchCompiler.compile("^From (.*) \
(.*):(.*):(.*)$"); Perl5Matcher sepMatch = new Perl5Matcher();
int c;
boolean inMessage = false;
StringBuffer messageBuffer = new StringBuffer();
String previousMessageSeparator = null;
boolean foundSep = false;
long prevMessageStart = ins.getFilePointer();
if (BUFFERING) {
String line = null;
while ((line = ins.readLine()) != null) {
foundSep = sepMatch.contains(line + "\n", sepMatchPattern);
if (foundSep && inMessage) {
// if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
// getLogger().debug(this.getClass().getName() + " Invoking " \
+ messAct.getClass() + " at " + prevMessageStart); // }
MimeMessage endResult = \
messAct.messageAction(previousMessageSeparator, messageBuffer.toString(), \
prevMessageStart); if (messAct.isComplete()) {
// I've got what I want so just exit
return endResult;
}
previousMessageSeparator = line;
prevMessageStart = ins.getFilePointer() - line.length() - 2;
messageBuffer = new StringBuffer();
inMessage = true;
}
// Only done at the start (first header)
if (foundSep && !inMessage) {
previousMessageSeparator = line.toString();
inMessage = true;
}
if (!foundSep && inMessage) {
messageBuffer.append(line).append("\n");
}
}
} else {
StringBuffer line = new StringBuffer();
while ((c = ins.read()) != -1) {
if (c == 10) {
foundSep = sepMatch.contains(line.toString(), sepMatchPattern);
if (foundSep && inMessage) {
// if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
// getLogger().debug(this.getClass().getName() + " \
Invoking " + messAct.getClass() + " at " + prevMessageStart); // \
}
MimeMessage endResult = \
messAct.messageAction(previousMessageSeparator, messageBuffer.toString(), \
prevMessageStart); if (messAct.isComplete()) {
// I've got what I want so just exit
return endResult;
}
previousMessageSeparator = line.toString();
prevMessageStart = ins.getFilePointer() - line.length();
messageBuffer = new StringBuffer();
inMessage = true;
}
// Only done at the start (first header)
if (foundSep && inMessage == false) {
previousMessageSeparator = line.toString();
inMessage = true;
}
if (!foundSep) {
messageBuffer.append(line).append((char) c);
}
line = new StringBuffer(); // Reset buffer
} else {
line.append((char) c);
}
}
}
if (messageBuffer.length() != 0) {
// process last message
return messAct.messageAction(previousMessageSeparator, \
messageBuffer.toString(), prevMessageStart); }
} catch (IOException ioEx) {
getLogger().error("Unable to write file (General I/O problem) " + \
mboxFile, ioEx); } catch (MalformedPatternException e) {
getLogger().error("Bad regex passed " + mboxFile, e);
} finally {
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Finished parsing ")
.append(mboxFile);
getLogger().debug(logBuffer.toString());
}
}
return null;
}
/**
* Find a given message
* This method will first use selectMessage(key) to see if the key/offset \
combination allows us to skip
* parts of the file and only load the message we are interested in
*
* @param key The key of the message to find
*/
private MimeMessage findMessage(String key) {
MimeMessage foundMessage = null;
// See if we can get the message by using the cache position first
foundMessage = selectMessage(key);
if (foundMessage == null) {
// If the message is not found something has changed from
// the cache. The cache may have been invalidated by
// another method, or the file may have been replaced from
// underneath us. Reload the cache, and try again.
mList = null;
loadKeys();
foundMessage = selectMessage(key);
}
return foundMessage;
}
/**
* Quickly find a message by using the stored message offsets
* @param key The key of the message to find
*/
private MimeMessage selectMessage(final String key) {
MimeMessage foundMessage = null;
// Can we find the key first
if (mList == null || !mList.containsKey(key)) {
// Not initiailised so no point looking
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" mList - key not found ")
.append(mboxFile);
getLogger().debug(logBuffer.toString());
}
return foundMessage;
}
long messageStart = ((Long) mList.get(key)).longValue();
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Load message starting at offset ")
.append(messageStart)
.append(" from file ")
.append(mboxFile);
getLogger().debug(logBuffer.toString());
}
// Now try and find the position in the file
RandomAccessFile ins = null;
try {
ins = new RandomAccessFile(mboxFile, "r");
if (messageStart != 0) {
ins.seek(messageStart );
}
MessageAction op = new MessageAction() {
public boolean isComplete() { return true; }
public MimeMessage messageAction(String messageSeparator, String \
bodyText, long messageStart) { try {
if (key.equals(generateKeyValue(bodyText))) {
getLogger().debug(this.getClass().getName() + " Located \
message. Returning MIME message"); return convertTextToMimeMessage(bodyText);
}
} catch (NoSuchAlgorithmException e) {
getLogger().error("MD5 not supported! ",e);
}
return null;
}
};
foundMessage = this.parseMboxFile(ins, op);
} catch (FileNotFoundException e) {
getLogger().error("Unable to save(open) file (File not found) " + \
mboxFile, e); } catch (IOException e) {
getLogger().error("Unable to write file (General I/O problem) " + \
mboxFile, e); } finally {
if (foundMessage == null) {
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" select - message not found ")
.append(mboxFile);
getLogger().debug(logBuffer.toString());
}
}
if (ins != null) try { ins.close(); } catch (IOException e) { \
getLogger().error("Unable to close file (General I/O problem) " + mboxFile, e); } }
return foundMessage;
}
/**
* Load the message keys and file pointer offsets from disk
*/
private synchronized void loadKeys() {
if (mList!=null) {
return;
}
RandomAccessFile ins = null;
try {
ins = new RandomAccessFile(mboxFile, "r");
long initialCapacity = (ins.length() > MLISTPRESIZEFACTOR ? ins.length() \
/MLISTPRESIZEFACTOR : 0); if (initialCapacity < DEFAULTMLISTCAPACITY ) {
initialCapacity = DEFAULTMLISTCAPACITY;
}
if (initialCapacity > Integer.MAX_VALUE) {
initialCapacity = Integer.MAX_VALUE - 1;
}
this.mList = new Hashtable((int)initialCapacity);
this.parseMboxFile(ins, new MessageAction() {
public boolean isComplete() { return false; }
public MimeMessage messageAction(String messageSeparator, String \
bodyText, long messageStart) { try {
String key = generateKeyValue(bodyText);
mList.put(key, new Long(messageStart));
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
getLogger().debug(this.getClass().getName() + " Key " + \
key + " at " + messageStart); }
} catch (NoSuchAlgorithmException e) {
getLogger().error("MD5 not supported! ",e);
}
return null;
}
});
//System.out.println("Done Load keys!");
} catch (FileNotFoundException e) {
getLogger().error("Unable to save(open) file (File not found) " + \
mboxFile, e); this.mList = new Hashtable((int)DEFAULTMLISTCAPACITY);
} catch (IOException e) {
getLogger().error("Unable to write file (General I/O problem) " + \
mboxFile, e); } finally {
if (ins != null) try { ins.close(); } catch (IOException e) { \
getLogger().error("Unable to close file (General I/O problem) " + mboxFile, e); } }
}
/**
* @see org.apache.james.services.MailRepository#store(Mail)
*/
public void store(Mail mc) {
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Will store message to file ")
.append(mboxFile);
getLogger().debug(logBuffer.toString());
}
this.mList = null;
// Now make up the from header
String fromHeader = null;
String message = null;
try {
message = getRawMessage(mc.getMessage());
// check for nullsender
if (mc.getMessage().getFrom() == null) {
fromHeader = "From " + dy.format(Calendar.getInstance().getTime());
} else {
fromHeader = "From " + mc.getMessage().getFrom()[0] + " " + \
dy.format(Calendar.getInstance().getTime()); }
} catch (IOException e) {
getLogger().error("Unable to parse mime message for " + mboxFile, e);
} catch (MessagingException e) {
getLogger().error("Unable to parse mime message for " + mboxFile, e);
}
// And save only the new stuff to disk
RandomAccessFile saveFile = null;
try {
saveFile = new RandomAccessFile(mboxFile, "rw");
saveFile.seek(saveFile.length()); // Move to the end
saveFile.writeBytes((fromHeader + "\n"));
saveFile.writeBytes((message + "\n"));
saveFile.close();
} catch (FileNotFoundException e) {
getLogger().error("Unable to save(open) file (File not found) " + \
mboxFile, e); } catch (IOException e) {
getLogger().error("Unable to write file (General I/O problem) " + \
mboxFile, e); }
}
/**
* @see org.apache.james.services.MailRepository#list()
*/
public Iterator list() {
loadKeys();
ArrayList keys = new ArrayList(mList.keySet());
if (keys.isEmpty() == false) {
// find the first message. This is a trick to make sure that if
// the file is changed out from under us, we will detect it and
// correct for it BEFORE we return the iterator.
findMessage((String) keys.iterator().next());
}
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" ")
.append(keys.size())
.append(" keys to be iterated over.");
getLogger().debug(logBuffer.toString());
}
if (fifo) Collections.sort(keys); // Keys is a HashSet; impose FIFO for apps \
that need it return keys.iterator();
}
/**
* @see org.apache.james.services.MailRepository#retrieve(String)
*/
public Mail retrieve(String key) {
loadKeys();
MailImpl res = null;
try {
MimeMessage foundMessage = findMessage(key);
if (foundMessage == null) {
getLogger().error("found message is null!");
return null;
}
res = new MailImpl(foundMessage);
res.setName(key);
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Retrieving entry for key ")
.append(key);
getLogger().debug(logBuffer.toString());
}
} catch (MessagingException e) {
getLogger().error("Unable to parse mime message for " + mboxFile + "\n" + \
e.getMessage(), e); }
return res;
}
/**
* @see org.apache.james.services.MailRepository#remove(Mail)
*/
public void remove(Mail mail) {
// Convert the message into a key
Vector delVec = new Vector();
delVec.addElement(mail);
remove(delVec);
}
/**
* Attempt to get a lock on the mbox by creating
* the file mboxname.lock
* @throws Exception
*/
private void lockMBox() throws Exception {
// Create the lock file (if possible)
String lockFileName = mboxFile + LOCKEXT;
int sleepCount = 0;
File mBoxLock = new File(lockFileName);
if (!mBoxLock.createNewFile()) {
// This is not good, somebody got the lock before me
// So wait for a file
while (!mBoxLock.createNewFile() && sleepCount < MAXSLEEPTIMES) {
try {
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Waiting for lock on file ")
.append(mboxFile);
getLogger().debug(logBuffer.toString());
}
Thread.sleep(LOCKSLEEPDELAY);
sleepCount++;
} catch (InterruptedException e) {
getLogger().error("File lock wait for " + mboxFile + " \
interrupted!",e);
}
}
if (sleepCount >= MAXSLEEPTIMES) {
throw new Exception("Unable to get lock on file " + mboxFile);
}
}
}
/**
* Unlock a previously locked mbox file
*/
private void unlockMBox() {
// Just delete the MBOX file
String lockFileName = mboxFile + LOCKEXT;
File mBoxLock = new File(lockFileName);
if (!mBoxLock.delete()) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Failed to delete lock file ")
.append(lockFileName);
getLogger().error(logBuffer.toString());
}
}
/**
* @see org.apache.james.services.MailRepository#remove(Collection)
*/
public void remove(final Collection mails)
{
if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
StringBuffer logBuffer =
new StringBuffer(128)
.append(this.getClass().getName())
.append(" Removing entry for key ")
.append(mails);
getLogger().debug(logBuffer.toString());
}
// The plan is as follows:
// Attempt to locate the message in the file
// by reading through the
// once we've done that then seek to the file
try {
RandomAccessFile ins = new RandomAccessFile(mboxFile, "r"); // The source
final RandomAccessFile outputFile = new RandomAccessFile(mboxFile + \
WORKEXT, "rw"); // The destination parseMboxFile(ins, new MessageAction() {
public boolean isComplete() { return false; }
public MimeMessage messageAction(String messageSeparator, String \
bodyText, long messageStart) {
// Write out the messages as we go, until we reach the key we \
want try {
String currentKey=generateKeyValue(bodyText);
boolean foundKey=false;
Iterator mailList = mails.iterator();
String key;
while (mailList.hasNext()) {
// Attempt to find the current key in the array
key = ((Mail)mailList.next()).getName();
if (key.equals(currentKey)) {
// Don't write the message to disk
foundKey = true;
break;
}
}
if (foundKey == false)
{
// We didn't find the key in the array so we will keep it
outputFile.writeBytes(messageSeparator + "\n");
outputFile.writeBytes(bodyText);
}
} catch (NoSuchAlgorithmException e) {
getLogger().error("MD5 not supported! ",e);
} catch (IOException e) {
getLogger().error("Unable to write file (General I/O problem) \
" + mboxFile, e); }
return null;
}
});
ins.close();
outputFile.close();
// Delete the old mbox file
File mbox = new File(mboxFile);
mbox.delete();
// And rename the lock file to be the new mbox
mbox = new File(mboxFile + WORKEXT);
if (!mbox.renameTo(new File(mboxFile)))
{
System.out.println("Failed to rename file!");
}
// Now delete the keys in mails from the main hash
Iterator mailList = mails.iterator();
String key;
while (mailList.hasNext()) {
// Attempt to find the current key in the array
key = ((Mail)mailList.next()).getName();
mList.remove(key);
}
} catch (FileNotFoundException e) {
getLogger().error("Unable to save(open) file (File not found) " + \
mboxFile, e); } catch (IOException e) {
getLogger().error("Unable to write file (General I/O problem) " + \
mboxFile, e); }
}
/**
* @see org.apache.james.services.MailRepository#remove(String)
*/
public void remove(String key) {
loadKeys();
try {
lockMBox();
} catch (Exception e) {
getLogger().error("Lock failed!",e);
return; // No lock, so exit
}
ArrayList keys = new ArrayList();
keys.add(key);
this.remove(keys);
unlockMBox();
}
/**
* @see org.apache.james.services.MailRepository#lock(String)
*/
public boolean lock(String key) {
return false;
}
/**
* @see org.apache.james.services.MailRepository#unlock(String)
*/
public boolean unlock(String key) {
return false;
}
/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
*/
public void configure(Configuration conf) throws ConfigurationException {
String destination;
this.mList = null;
BUFFERING = conf.getAttributeAsBoolean("BUFFERING", true);
fifo = conf.getAttributeAsBoolean("FIFO", false);
destination = conf.getAttribute("destinationURL");
if (destination.charAt(destination.length() - 1) == '/') {
// Remove the trailing / as well as the protocol marker
mboxFile = destination.substring("mbox://".length(), \
destination.lastIndexOf("/")); } else {
mboxFile = destination.substring("mbox://".length());
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("MBoxMailRepository.destinationURL: " + destination);
}
String checkType = conf.getAttribute("type");
if (!(checkType.equals("MAIL") || checkType.equals("SPOOL"))) {
String exceptionString = "Attempt to configure MboxMailRepository as " + \
checkType; if (getLogger().isWarnEnabled()) {
getLogger().warn(exceptionString);
}
throw new ConfigurationException(exceptionString);
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-user-unsubscribe@james.apache.org
For additional commands, e-mail: server-user-help@james.apache.org
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic