📄 mboxfolder.java
字号:
/*
* MboxFolder.java
* Copyright (C) 1999 dog <dog@dog.net.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* You may retrieve the latest version of this library from
* http://www.dog.net.uk/knife/
*
* Contributor(s): Daniel Thor Kristjan <danielk@cat.nyu.edu> close and expunge clarification.
* Sverre Huseby <sverrehu@online.no> gzipped mailboxes
*/
package dog.mail.mbox;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;
import javax.mail.*;
import javax.mail.event.*;
import javax.mail.internet.*;
import dog.mail.util.*;
/**
* The folder class implementing a UNIX mbox-format mailbox.
*
* @author dog@dog.net.uk
* @version 1.2.1
*/
public class MboxFolder extends Folder {
File file;
Vector messages = new Vector();
boolean open = false;
int type = HOLDS_MESSAGES;
/**
* Constructor.
*/
protected MboxFolder(Store store, String filename) {
super(store);
file = new File(filename);
if (file.exists() && file.isDirectory())
type = HOLDS_FOLDERS;
}
/**
* Returns the name of this folder.
*/
public String getName() {
return file.getName();
}
/**
* Returns the full name of this folder.
*/
public String getFullName() {
return file.getAbsolutePath();
}
/**
* Returns the type of this folder.
* @exception MessagingException if a messaging error occurred
*/
public int getType() throws MessagingException {
return type;
}
/**
* Indicates whether this folder exists.
* @exception MessagingException if a messaging error occurred
*/
public boolean exists() throws MessagingException {
return file.exists();
}
/**
* Indicates whether this folder contains new messages.
* @exception MessagingException if a messaging error occurred
*/
public boolean hasNewMessages() throws MessagingException {
return getNewMessageCount()>0;
}
/**
* Opens this folder.
* @exception MessagingException if a messaging error occurred
*/
public void open(int mode) throws MessagingException {
switch (mode) {
case READ_WRITE:
if (!file.canWrite())
throw new MessagingException("Folder is read-only");
case READ_ONLY:
}
if (!file.canRead())
throw new MessagingException("Can't read folder");
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new CRLFInputStream(getInputStream())));
String line = reader.readLine();
if (line!=null && !line.startsWith("From "))
throw new MessagingException("Mailbox format error", new ProtocolException());
} catch (IOException e) {
throw new MessagingException("Unable to open folder", e);
}
open = true;
notifyConnectionListeners(ConnectionEvent.OPENED);
}
/**
* Closes this folder.
* @param expunge if the folder is to be expunged before it is closed
* @exception MessagingException if a messaging error occurred
*/
public void close(boolean expunge) throws MessagingException {
if (open) {
if (expunge) expunge();
open = false;
notifyConnectionListeners(ConnectionEvent.CLOSED);
}
// save the changes
synchronized (this) {
try {
OutputStream os = new BufferedOutputStream(getOutputStream());
Message[] m = new Message[messages.size()];
messages.copyInto(m);
for (int i=0; i<m.length; i++) {
Address[] f = m[i].getFrom();
String top = "From "+((f.length>0) ? f[0].toString() : "-")+ " "+m[i].getSentDate()+"\n";
os.write(top.getBytes());
m[i].writeTo(os);
}
os.close();
} catch (IOException e) {
throw new MessagingException("I/O error writing mailbox", e);
}
}
}
/**
* Expunges this folder.
* This deletes all the messages marked as deleted.
* @exception MessagingException if a messaging error occurred
*/
public synchronized Message[] expunge() throws MessagingException {
Vector ve = new Vector();
if (open && messages!=null) {
for (Enumeration enum = messages.elements(); enum.hasMoreElements(); ) {
Message message = (Message)enum.nextElement();
Flags flags = message.getFlags();
if (flags.contains(Flags.Flag.DELETED)) {
messages.removeElement(message);
ve.addElement(message);
}
}
}
Message[] expunged = new Message[ve.size()];
ve.copyInto(expunged);
notifyMessageRemovedListeners(true, expunged);
return expunged;
}
/**
* Indicates whether this folder is open.
*/
public boolean isOpen() {
return open;
}
/**
* Returns the permanent flags for this folder.
*/
public Flags getPermanentFlags() { return new Flags(); }
/**
* Returns the number of messages in this folder.
* @exception MessagingException if a messaging error occurred
*/
public int getMessageCount() throws MessagingException {
return getMessages().length;
}
/**
* Returns the specified message number from this folder.
* @exception MessagingException if a messaging error occurred
*/
public Message getMessage(int msgnum) throws MessagingException {
try {
return getMessages()[msgnum];
} catch (ArrayIndexOutOfBoundsException e) {
throw new MessagingException("No such message", e);
}
}
/**
* Returns the messages in this folder.
* @exception MessagingException if a messaging error occurred
*/
public synchronized Message[] getMessages() throws MessagingException {
if (messages!=null) {
Vector added = new Vector();
int count = 0;
try {
RandomAccessFile raf = new RandomAccessFile(file, "r");
String line;
for (line = raf.readLine(); line!=null; line = raf.readLine()) {
if (line.startsWith("From ")) { // new message
Message message = new MboxMessage(this, raf, count++);
added.addElement(message);
messages.addElement(message);
}
}
raf.close();
} catch (IOException e) {
throw new MessagingException("I/O error reading mailbox", e);
}
if (added.size()>0) {
Message[] n = new Message[added.size()]; added.copyInto(n);
notifyMessageAddedListeners(n);
}
}
Message[] m = new Message[messages.size()]; messages.copyInto(m);
return m;
}
public synchronized void appendMessages(Message[] messages) throws MessagingException {
Vector added = new Vector();
for (int i=0; i<messages.length; i++) {
if (messages[i] instanceof MimeMessage)
added.addElement(new MboxMessage(this, (MimeMessage)messages[i], i));
}
if (added.size()>0) {
Message[] n = new Message[added.size()]; added.copyInto(n);
notifyMessageAddedListeners(n);
}
}
/**
* Does nothing.
* The messages <i>must</i> be fetched in their entirety by getMessages() -
* this is the nature of the Mbox protocol.
* @exception MessagingException ignore
*/
public void fetch(Message amessage[], FetchProfile fetchprofile) throws MessagingException {
}
/**
* Returns the parent folder.
*/
public Folder getParent() throws MessagingException {
return store.getFolder(file.getParent());
}
/**
* Returns the subfolders of this folder.
*/
public Folder[] list() throws MessagingException {
if (type!=HOLDS_FOLDERS)
throw new MessagingException("This folder can't contain subfolders");
try {
String[] files = file.list();
Folder[] folders = new Folder[files.length];
for (int i=0; i<files.length; i++)
folders[i] = store.getFolder(file.getAbsolutePath()+File.separator+files[i]);
return folders;
} catch (SecurityException e) {
throw new MessagingException("Access denied", e);
}
}
/**
* Returns the subfolders of this folder matching the specified pattern.
*/
public Folder[] list(String pattern) throws MessagingException {
if (type!=HOLDS_FOLDERS)
throw new MessagingException("This folder can't contain subfolders");
try {
String[] files = file.list(new MboxFilenameFilter(pattern));
Folder[] folders = new Folder[files.length];
for (int i=0; i<files.length; i++)
folders[i] = store.getFolder(file.getAbsolutePath()+File.separator+files[i]);
return folders;
} catch (SecurityException e) {
throw new MessagingException("Access denied", e);
}
}
/**
* Returns the separator character.
*/
public char getSeparator() throws MessagingException {
return File.separatorChar;
}
/**
* Creates this folder in the store.
*/
public boolean create(int type) throws MessagingException {
if (file.exists())
throw new MessagingException("Folder already exists");
switch (type) {
case HOLDS_FOLDERS:
try {
file.mkdirs();
this.type = type;
notifyFolderListeners(FolderEvent.CREATED);
return true;
} catch (SecurityException e) {
throw new MessagingException("Access denied", e);
}
case HOLDS_MESSAGES:
try {
// save the changes
synchronized (this) {
if (messages==null) messages = new Vector();
OutputStream os = new BufferedOutputStream(getOutputStream());
Message[] m = new Message[messages.size()]; messages.copyInto(m);
for (int i=0; i<m.length; i++) {
Address[] f = m[i].getFrom();
String top = "From "+((f.length>0) ? f[0].toString() : "-")+" "+m[i].getSentDate()+"\n";
os.write(top.getBytes());
m[i].writeTo(os);
}
os.close();
}
this.type = type;
notifyFolderListeners(FolderEvent.CREATED);
return true;
} catch (IOException e) {
throw new MessagingException("I/O error writing mailbox", e);
} catch (SecurityException e) {
throw new MessagingException("Access denied", e);
}
}
return false;
}
/**
* Deletes this folder.
*/
public boolean delete(boolean recurse) throws MessagingException {
if (recurse) {
try {
if (type==HOLDS_FOLDERS) {
Folder[] folders = list();
for (int i=0; i<folders.length; i++)
if (!folders[i].delete(recurse))
return false;
}
file.delete();
notifyFolderListeners(FolderEvent.DELETED);
return true;
} catch (SecurityException e) {
throw new MessagingException("Access denied", e);
}
} else {
try {
if (type==HOLDS_FOLDERS) {
Folder[] folders = list();
if (folders.length>0)
return false;
}
file.delete();
notifyFolderListeners(FolderEvent.DELETED);
return true;
} catch (SecurityException e) {
throw new MessagingException("Access denied", e);
}
}
}
/**
* Mbox folders cannot be created, deleted, or renamed.
*/
public boolean renameTo(Folder folder) throws MessagingException {
try {
String filename = folder.getFullName();
if (filename!=null) {
file.renameTo(new File(filename));
((MboxStore)store).folders.clear();
notifyFolderListeners(FolderEvent.RENAMED);
return true;
} else
throw new MessagingException("Illegal filename: null");
} catch (SecurityException e) {
throw new MessagingException("Access denied", e);
}
}
/**
* Mbox folders cannot contain subfolders.
*/
public Folder getFolder(String filename) throws MessagingException {
return store.getFolder(file.getAbsolutePath()+File.separator+filename);
}
/**
* Checks if the current file is or is supposed to be
* compressed. Uses the filename to figure it out.
*/
private boolean isGzip() {
return file.getName().toLowerCase().endsWith(".gz");
}
/**
* Creates an output stream that possibly will compress
* whatever is sent to it, based on the current filename.
*/
private OutputStream getOutputStream() throws IOException {
OutputStream out;
out = new FileOutputStream(file);
if (isGzip())
out = new GZIPOutputStream(out);
return out;
}
/**
* Creates an input stream that possibly will decompress the
* file contents.
*/
private InputStream getInputStream() throws IOException {
InputStream in;
in = new FileInputStream(file);
if (isGzip())
in = new GZIPInputStream(in);
return in;
}
class MboxFilenameFilter implements FilenameFilter {
String pattern;
int asteriskIndex, percentIndex;
MboxFilenameFilter(String pattern) {
this.pattern = pattern;
asteriskIndex = pattern.indexOf('*');
percentIndex = pattern.indexOf('%');
}
public boolean accept(File directory, String name) {
if (asteriskIndex>-1) {
String start = pattern.substring(0, asteriskIndex), end = pattern.substring(asteriskIndex+1, pattern.length());
return (name.startsWith(start) && name.endsWith(end));
} else if (percentIndex>-1) {
String start = pattern.substring(0, percentIndex), end = pattern.substring(percentIndex+1, pattern.length());
return (directory.equals(file) && name.startsWith(start) && name.endsWith(end));
}
return name.equals(pattern);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -