You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by da...@apache.org on 2002/08/27 15:57:29 UTC
cvs commit: jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands FileStoreHighestUID.java FileMailbox.java CommandFetch.java HighestUID.java
danny 2002/08/27 06:57:29
Added: proposals/imap/java/org/apache/james/imapserver/commands
FileStoreHighestUID.java FileMailbox.java
CommandFetch.java HighestUID.java
Log:
latest changes from sascha
Revision Changes Path
1.1 jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands/FileStoreHighestUID.java
Index: FileStoreHighestUID.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.imapserver;
import java.io.*;
import java.util.*;
/**
* Reference: RFC 2060
* @author <a href="mailto:s@rapi.com">Stephan Schiessling</a>
* @version 0.1 on 15 Aug 2002
*/
public class FileStoreHighestUID implements HighestUID {
private int highestUID;
private int whenToWrite;
private static final int WRITE_STEP = 3;
private File file;
public FileStoreHighestUID(File f) {
file = f;
highestUID = 0;
if (file.exists()) {
ObjectInputStream is = null;
try {
is = new ObjectInputStream(new FileInputStream(file));
Integer i = (Integer) is.readObject();
highestUID = i.intValue();
is.close();
is = null;
} catch (Exception ex) {
// log here
ex.printStackTrace();
if (is != null) {
try {
is.close();
} catch (Exception ignored) {}
}
throw new RuntimeException("Could not load highestUID!");
}
// maybe james was stopped without writing correct highestUID, therefore add
// STEP_HIGHEST_UID, to ensure uniqeness of highestUID.
highestUID += WRITE_STEP;
}
write();
whenToWrite = highestUID+WRITE_STEP;
System.out.println("Initialized highestUID="+highestUID);
}
public synchronized int get() {
return highestUID;
}
public synchronized void increase() {
highestUID++;
if (highestUID >= whenToWrite) {
// save this highestUID
whenToWrite = highestUID+WRITE_STEP;
// make it persistent
write();
}
}
private void write() {
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream( new FileOutputStream(file));
os.writeObject(new Integer(highestUID));
os.close();
os = null;
} catch (Exception ex) {
// log here
ex.printStackTrace();
if (os != null) {
try {
os.close();
} catch (Exception ignored) {}
}
throw new RuntimeException("Failed to save highestUID!");
}
}
}
1.1 jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands/FileMailbox.java
Index: FileMailbox.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.imapserver;
import org.apache.avalon.cornerstone.services.store.ObjectRepository;
import org.apache.avalon.cornerstone.services.store.Store;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.phoenix.BlockContext;
import org.apache.james.AccessControlException;
import org.apache.james.AuthorizationException;
import org.apache.james.core.MimeMessageWrapper;
import org.apache.james.services.UsersRepository;
import org.apache.james.services.UsersStore;
import org.apache.james.util.Assert;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeMessage;
import javax.mail.MessagingException;
import java.io.*;
import java.util.*;
/**
* Object representing an IMAP4rev1 mailbox (folder) on a local file system.
* The mailbox contains messages, message attributes and an access control
* list.
*
* <p> from Interface Mailbox
*
* <p>Mailbox Related Flags (rfc2060 name attributes)
* <br> \Noinferiors It is not possible for any child levels of hierarchy
* to exist under this name; no child levels exist now and none can be created
* in the future.
* <br> \Noselect It is not possible to use this name as a selectable
* mailbox.
* <br> \Marked The mailbox has been marked "interesting" by the
* server; the mailbox probably contains messages that have been added since
* the last time the mailbox was selected.
* <br> \Unmarked The mailbox does not contain any additional
* messages since the last time the mailbox was selected.
*
* <p>Message related flags.
* <br>The flags allowed per message are specific to each mailbox.
* <br>The minimum list (rfc2060 system flags) is:
* <br> \Seen Message has been read
* <br> \Answered Message has been answered
* <br> \Flagged Message is "flagged" for urgent/special attention
* <br> \Deleted Message is "deleted" for removal by later EXPUNGE
* <br> \Draft Message has not completed composition (marked as a draft).
* <br> \Recent Message is "recently" arrived in this mailbox. This
* session is the first session to have been notified about this message;
* subsequent sessions will not see \Recent set for this message. This flag
* can not be altered by the client.
* <br> If it is not possible to determine whether or not this
* session is the first session to be notified about a message, then that
* message SHOULD be considered recent.
*
* <p> From interface ACL </p>
*
* The standard rights in RFC2086 are:
* <br>l - lookup (mailbox is visible to LIST/LSUB commands)
* <br>r - read (SELECT the mailbox, perform CHECK, FETCH, PARTIAL, SEARCH,
* COPY from mailbox)
* <br>s - keep seen/unseen information across sessions (STORE SEEN flag)
* <br>w - write (STORE flags other than SEEN and DELETED)
* <br>i - insert (perform APPEND, COPY into mailbox)
* <br>p - post (send mail to submission address for mailbox, not enforced by
* IMAP4 itself)
* <br>c - create (CREATE new sub-mailboxes in any implementation-defined
* hierarchy)
* <br>d - delete (STORE DELETED flag, perform EXPUNGE)
* <br>a - administer (perform SETACL)
*
* <p> Serialization. Not all fields are serialized. Dispose() must be called to
* write serialized fiels to disc before finishing with this object.
*
* <p> Deserialization. On recover from disc, configure, compose,
* contextualize and reInit must be called before object is ready for use.
*
* Reference: RFC 2060
* @author <a href="mailto:sascha@kulawik.de">Sascha Kulawik</a>
* @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
* @version 0.2 on 04 Aug 2002
*/
public class FileMailbox
extends AbstractLogEnabled
implements ACLMailbox, Serializable {
public static final String MAILBOX_FILE_NAME = "mailbox.mbr";
private static final String MESSAGE_EXTENSION = ".msg";
private static final String ATTRIBUTES_EXTENSION = ".att";
private static final String FLAGS_EXTENSION = ".flags";
private static final int NUMBER_OF_RIGHTS = 9;
// Map string identities to boolean[NUMBER_OF_RIGHTS] arrays of rights
//The rights are, in order: l,r,s,w,i,p,c,d,a
private static final int LOOKUP = 0;
private static final int READ = 1;
private static final int KEEP_SEEN = 2;
private static final int WRITE = 3;
private static final int INSERT = 4;
private static final int POST = 5;
private static final int CREATE = 6;
private static final int DELETE = 7;
private static final int ADMIN = 8;
private static final boolean[] NO_RIGHTS
= {false, false, false, false, false, false, false, false, false};
private static final boolean[] ALL_RIGHTS
= {true, true, true, true, true, true, true, true, true};
private static final String DENY_ACCESS = "Access denied by ACL";
private static final String DENY_AUTH = "Action not authorized for: ";
private static final String OPTIONAL_RIGHTS = "l r s w i p c d a";
private static final char[] DELETE_MODS
= {'-', 'l', 'r', 's', 'w', 'i', 'p', 'c', 'd', 'a'};
/* Transient fields - reInit must be called on recover from disc. */
private transient BlockContext context;
private transient Configuration conf;
private transient ComponentManager compMgr;
private transient UsersRepository localUsers;
private transient HashSet listeners;
/* Serialized fileds */
private String path; // does not end with File.separator
private String rootPath; // does not end with File.separator
private File directory ;
private String owner;
private String absoluteName;
private Map acl;
private String name;
private int uidValidity;
private int mailboxSize; // octets
private boolean inferiorsAllowed;
private boolean marked;
private boolean notSelectableByAnyone;
//Addon by s@rapi.com. Sets the UID for all Mailboxes
private static HighestUID highestUID;
// The message sequence number of a msg is its index in List sequence + 1
private List sequence; //List of UIDs of messages in mailbox
// Set of UIDs of messages with recent flag set
private Set recentMessages;
// Set of UIDs of messages with delete flag set
private Set messagesForDeletion;
//map of user String to Integer uid, 0 for no unseen messages
private Map oldestUnseenMessage;
// Set of subscribed users.
private Set subscribedUsers = new HashSet(1000);
public void configure(Configuration conf) throws ConfigurationException {
this.conf = conf;
highestUID = new FileStoreHighestUID(new File(conf.getChild("recordRepository").getValue()+File.separator+"#CONF.GLOBAL.uid"));
}
public void contextualize(Context context) {
this.context = (BlockContext)context;
}
public void compose(ComponentManager comp) {
compMgr = comp;
}
public void prepareMailbox(String user, String absName, String initialAdminUser, int uidValidity ) {
Assert.isTrue( Assert.ON && user != null && user.length() > 0 );
owner = user;
Assert.isTrue( Assert.ON && absName != null && (absName.length() > 0));
absoluteName = absName;
Assert.isTrue( Assert.ON && initialAdminUser != null && initialAdminUser.length() > 0 );
acl = new HashMap(7);
acl.put(initialAdminUser, ALL_RIGHTS);
Assert.isTrue( Assert.ON && uidValidity > 0 );
this.uidValidity = uidValidity;
}
public void initialize() throws Exception {
mailboxSize = 0;
inferiorsAllowed = true;
marked = false;
notSelectableByAnyone = false;
oldestUnseenMessage = new HashMap();
listeners = new HashSet();
sequence = new ArrayList();
recentMessages = new HashSet();
messagesForDeletion = new HashSet();
getLogger().info("FileMailbox init for " + absoluteName);
UsersStore usersStore = (UsersStore)compMgr.lookup( "org.apache.james.services.UsersStore" );
localUsers = usersStore.getRepository("LocalUsers");
rootPath = conf.getChild( "mailboxRepository" ).getValue();
if (!rootPath.endsWith(File.separator)) {
rootPath = rootPath + File.separator;
}
path = getPath( absoluteName, owner, rootPath );
name = absoluteName.substring(absoluteName.lastIndexOf( JamesHost.HIERARCHY_SEPARATOR ) + 1);
if (name.equals(owner)) {
name = "";
}
//Check for writable directory
getLogger().info("MailboxDir " + path);
System.out.println("MailboxDir TO WRITE TO " + path);
File mailboxDir = new File(path);
if (mailboxDir.exists()) {
throw new RuntimeException("Error: Attempt to overwrite mailbox directory at " + path);
} else if (! mailboxDir.mkdir()){
throw new RuntimeException("Error: Cannot create mailbox directory at " + path);
} else if (!mailboxDir.canWrite()) {
throw new RuntimeException("Error: Cannot write to directory at " + path);
}
writeMailbox();
getLogger().info("FileMailbox init complete: " + absoluteName);
}
/**
* Return the file-system path to a given absoluteName mailbox.
*
* @param absoluteName the user-independent name of the mailbox
* @param owner string name of owner of mailbox
*/
private String getPath( String absoluteName, String owner, String rootPath )
{
Assert.isTrue( Assert.ON &&
absoluteName.startsWith( JamesHost.NAMESPACE_TOKEN ) );
// Remove the leading '#' and replace Hierarchy separators with file separators.
String filePath = absoluteName.substring( JamesHost.NAMESPACE_TOKEN.length() );
filePath = filePath.replace( JamesHost.HIERARCHY_SEPARATOR_CHAR, File.separatorChar );
return rootPath + filePath;
}
/**
* Re-initialises mailbox after reading from file-system. Cannot assume that this is the same instance of James that wrote it.
*
* <p> Contract is that re-init must be called after configure, contextualize, compose.
*/
public void reinitialize() throws Exception {
listeners = new HashSet();
getLogger().info("FileMailbox reInit for " + absoluteName);
UsersStore usersStore = (UsersStore)compMgr.lookup( "org.apache.james.services.UsersStore" );
localUsers = usersStore.getRepository("LocalUsers");
rootPath
= conf.getChild("mailboxRepository").getValue();
if (!rootPath.endsWith(File.separator)) {
rootPath = rootPath + File.separator;
}
path = getPath( absoluteName, owner, rootPath );
}
/**
* Call when host has finished with a mailbox.
* This is really a stop rather than destroy.
* Writes current mailbox object to disc.
*/
public void dispose() {
writeMailbox();
getLogger().info("FileMailbox object destroyed: " + absoluteName);
}
/**
* Permanently deletes the mailbox.
*/
public void removeMailbox()
{
// First delete the mailbox file
path = getPath( absoluteName, owner, rootPath );
String mailboxRecordFile = path + File.separator + MAILBOX_FILE_NAME;
File mailboxRecord = new File( mailboxRecordFile );
Assert.isTrue( Assert.ON &&
mailboxRecord.exists() &&
mailboxRecord.isFile() );
mailboxRecord.delete();
// Check for empty directory before deleting.
File mailboxDir = new File(path);
Assert.isTrue( Assert.ON &&
mailboxDir.exists() );
Assert.isTrue( Assert.ON &&
mailboxDir.isDirectory() );
Assert.isTrue( Assert.ON &&
mailboxDir.list().length == 0 );
mailboxDir.delete();
}
/**
* Renames this Mailbox.
* @param usernmae The Username who calles this Command.
* @param newmailboxname The new name for this Mailbox.
* @returns true if everythink was sucessfully, else false.
* @throws MailboxException if mailbox does not exist locally.
* @throws AuthorizationException if the user has no rights for changing the name of the Mailbox.
*/
public boolean renameMailbox(String username, String newmailboxname) throws MailboxException, AuthorizationException {
try {
path = getPath( absoluteName, owner, rootPath );
StringTokenizer strt = new StringTokenizer(newmailboxname,".");
String lastnameofmailbox="";
while(strt.hasMoreTokens())
lastnameofmailbox=strt.nextToken();
File fle = new File(this.path);
fle.renameTo(new File(fle.getParent(), lastnameofmailbox));
this.path=fle.getParent()+File.separator+lastnameofmailbox;
this.absoluteName = this.absoluteName.substring(0,this.absoluteName.length()-this.name.length())+lastnameofmailbox;
this.name=lastnameofmailbox;
this.writeMailbox();
return true;
}catch(Exception e) {
e.printStackTrace();
return false;
}
}
/**
* THIS IS AN INTERIM SOLUTION !
*
* @param usernmae The Username who calles this Command.
* @param oldabsolutename The old name of the parent.
* @param newabsolutename The new name for the parent.
* @returns true if everythink was sucessfully, else false.
* @throws MailboxException if mailbox does not exist locally.
* @throws AuthorizationException if the user has no rights for changing the name of the Mailbox.
*/
public boolean renameSubMailbox(String username, String oldabsolutename, String newname) {
try {
System.out.println("renameSubMailbox ABSOLUTE NAME "+this.absoluteName);
StringTokenizer strt = new StringTokenizer(oldabsolutename,".");
StringBuffer strbuff = new StringBuffer();
for(int i=0;i<strt.countTokens();i++){
String token = strt.nextToken();
if(strbuff.length()>0) strbuff.append(".");
strbuff.append(token);
}
strbuff.append(".");
strbuff.append(newname);
this.absoluteName = strbuff.toString()+this.absoluteName.substring(oldabsolutename.length());
System.out.println("renameSubMailbox TOKEN CONVERTED: "+this.absoluteName);
this.writeMailbox();
return true;
}catch(Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Returns true once this Mailbox has been checkpointed.
* This implementation just writes its mailbox record to disc. Unless something is
* broken all messages added, amended or removed from this mailbox will have been
* handled by this object.
* <br> This implementation always returns true.
*
* @returns true
*/
public synchronized boolean checkpoint() {
writeMailbox();
getLogger().info("FileMailbox: " + absoluteName + " checkpointed.");
return true;
}
/**
* Remove \Recent flag from all messages in mailbox. Should be called
* whenever a user session finishes.
*/
public synchronized void unsetRecent() {
Iterator it = recentMessages.iterator();
while(it.hasNext()) {
Integer uidObj =(Integer)it.next();
int uid = uidObj.intValue();
Flags flags = readFlags(uid);
if (flags != null) {
flags.setRecent(false);
writeFlags(uid, flags);
}
}
recentMessages.clear();
}
// Methods that don't involve the ACL ------------------
/**
* Returns name of this mailbox relative to its parent in the mailbox
* hierarchy.
* Example: 'NewIdeas'
*
* @returns String name of mailbox relative to its immeadiate parent in
* the mailbox hierarchy.
*/
public String getName() {
return name;
}
/**
* Returns absolute, that is user-independent, hierarchical name of
* mailbox (including namespace)
* Example: '#mail.fred.flintstone.apache.James.NewIdeas'
*
* @returns String name of mailbox in absolute form
*/
public String getAbsoluteName() {
return absoluteName;
}
/** Returns namespace starting with namespace token.
* Example: '#mail'
*
* @returns String containing user-independent namespace of this mailbox.
*/
// public String getNamespace();
/** Returns true if the argument is the relative or absolute name of
* this mailbox
*
* @param name possible name for this Mailbox
* @returns true if name matches either getName() or getAbsoluteName()
*/
public boolean matchesName(String testName) {
return (name.equals(testName) || name.equals(absoluteName));
}
/**
* Returns the current unique id validity value of this mailbox.
*
* @returns int current 32 bit unique id validity value of this mailbox
*/
public int getUIDValidity() {
return uidValidity;
}
/**
* Returns the 32 bit uid available for the next message.
*
* @returns int the next UID that would be used.
*/
public int getNextUID() {
return highestUID.get() + 1;
}
/**
* Returns mailbox size in octets. Should only include actual messages
* and not any implementation-specific data, such as message attributes.
*
* @returns int mailbox size in octets
*/
public synchronized int getMailboxSize() {
return mailboxSize;
}
/**
* Indicates if child folders may be created. It does not indicate which
* users can create child folders.
*
* @returns boolean TRUE if inferiors aree allowed
*/
public boolean getInferiorsAllowed() {
return inferiorsAllowed;
}
/**
* Indicates that messages have been added since this mailbox was last
* selected by any user.
*
* @returns boolean TRUE if new messages since any user last selected
* mailbox
*/
public synchronized boolean isMarked() {
return marked;
}
/**
* Returns all flags supported by this mailbox.
* e.g. \Answered \Deleted
*
* @returns String a space seperated list of message flags which are
* supported by this mailbox.
*/
public String getSupportedFlags() {
return SYSTEM_FLAGS;
}
/**
* Indicates no of messages with \Recent flag set
*
* @returns int no of messages with \Recent flag set
*/
public synchronized int getRecent() {
return recentMessages.size();
}
/**
* Indicates the oldest unseen message for the specified user.
*
* @returns int Message Sequence Number of first message without \Seen
* flag set for this User. 0 means no unseen messages in this mailbox.
*/
public synchronized int getOldestUnseen(String user) {
int response = 0;
if (oldestUnseenMessage.containsKey(user)) {
Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
if (! (uidObj.intValue() == 0)) {
response = sequence.indexOf(uidObj) + 1;
}
} else {
if (sequence.size() > 0) {
response = 1;
oldestUnseenMessage.put(user, (Integer)sequence.get(0));
} else {
oldestUnseenMessage.put(user, (new Integer(0)));
}
}
return response;
}
/**
* Indicates number of messages in folder
*
* @returns int number of messages
*/
public synchronized int getExists() {
return sequence.size();
}
/**
* Indicates the number of unseen messages for the specified user.
*
* @returns int number of messages without \Seen flag set for this User.
*/
public int getUnseen(String user) {
if (oldestUnseenMessage.containsKey(user)) {
int response = 0; //indicates no unseen messages
Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
int oldUID = uidObj.intValue();
if (oldUID != 0) {
ListIterator lit
= sequence.listIterator(sequence.indexOf(uidObj));
while (lit.hasNext() ) {
int uid = ((Integer)lit.next()).intValue();
Flags flags = readFlags(uid);
if (!flags.isSeen(user)) {
response ++;
}
}
}
return response;
} else { // user has never selected mailbox
return sequence.size();
}
}
/** Mailbox Events are used to inform registered listeners of events in the Mailbox.
* E.g. if mail is delivered to an Inbox or if another user appends/ deletes a message.
*/
public synchronized void addMailboxEventListener(MailboxEventListener mel) {
listeners.add(mel);
}
public synchronized void removeMailboxEventListener(MailboxEventListener mel) {
listeners.remove(mel);
}
/**
* Mark this mailbox as not selectable by anyone.
* Example folders at the roots of hierarchies, e. #mail for each user.
*
* @param state true if folder is not selectable by anyone
*/
public void setNotSelectableByAnyone(boolean state) {
notSelectableByAnyone = state;
}
public boolean isNotSelectableByAnyone() {
return notSelectableByAnyone;
}
// Methods for the embedded ACL ------------------------
/**
* Store access rights for a given identity.
* The setter is the user setting the rights, the identifier is the user
* whose rights are affected.
* The setter and identifier arguments must be non-null and non-empty.
* The modification argument must be non-null and follow the syntax of the
* third argument to a SETACL command.
* If the modification argument is an empty string, that identifier is
* removed from the ACL, if currently present.
*
* @param setter String representing user attempting to set rights, must
* be non-null and non-empty
* @param identity String representing user whose rights are being set,
* must be non-null and non-empty
* @param modification String representing the change in rights, following
* the syntax specified in rfc 2086. Note a blank string means delete all
* rights for given identity.
* @returns true if requested modification succeeded. A return value of
* false means an error other than an AccessControlException or
* AuthorizationException.
* @throws AccessControlException if setter does not have lookup rights for
* this mailbox (ie they should not know this mailbox exists).
* @throws AuthorizationException if specified setter does not have the
* administer right (ie the right to write ACL rights), or if the result
* of this method would leave no identities with admin rights.
*/
public boolean setRights(String setter, String identifier,
String modification)
throws AccessControlException, AuthorizationException {
boolean[] settersRights = (boolean[]) acl.get(setter);
if (settersRights == null
|| (settersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
} else if (settersRights[ADMIN] == false) {
throw new AuthorizationException(DENY_AUTH + setter);
}
boolean[] existingRights = (boolean[]) acl.get(identifier);
char[] mods = modification.toCharArray();
if (mods.length == 0) { // means delete all
mods = DELETE_MODS;
}
if(existingRights == null) {
if ( mods[0] == REMOVE_RIGHTS ) {
return false;
} else {
existingRights = new boolean[NUMBER_OF_RIGHTS];
System.arraycopy(NO_RIGHTS, 0, existingRights, 0,
NUMBER_OF_RIGHTS);
}
}
boolean change;
boolean[] rights = new boolean[NUMBER_OF_RIGHTS];
if (mods[0] == ADD_RIGHTS) {
change = true;
System.arraycopy(existingRights, 0, rights, 0,
NUMBER_OF_RIGHTS);
} else if (mods[0] == REMOVE_RIGHTS) {
change = false;
System.arraycopy(existingRights, 0, rights, 0,
NUMBER_OF_RIGHTS);
} else { // means replace
System.arraycopy(NO_RIGHTS, 0, rights, 0,
NUMBER_OF_RIGHTS);
char[] new_mods = new char[mods.length + 1];
System.arraycopy(mods, 0, new_mods, 1, mods.length);
mods = new_mods;
change = true;
}
for (int i=1; i <mods.length; i++) {
switch(mods[i]) {
case LOOKUP_RIGHTS: rights[LOOKUP] = change;
break;
case READ_RIGHTS: rights[READ] = change;
break;
case KEEP_SEEN_RIGHTS: rights[KEEP_SEEN] = change;
break;
case WRITE_RIGHTS: rights[WRITE] = change;
break;
case INSERT_RIGHTS: rights[INSERT] = change;
break;
case POST_RIGHTS: rights[POST] = change;
break;
case CREATE_RIGHTS: rights[CREATE] = change;
break;
case DELETE_RIGHTS: rights[DELETE] = change;
break;
case ADMIN_RIGHTS: rights[ADMIN] = change;
break;
default: return false;
}
}
// All rights above lookup require lookup
if(rights[LOOKUP] == false && !Arrays.equals(rights, NO_RIGHTS)) {
return false;
}
// Each right requires all the rights before it.
int count = 0;
for (int i=1; i< NUMBER_OF_RIGHTS; i++) {
if(rights[i-1] ^ rights[i]) {
count++;
}
}
switch (count) {
case 0: // now Admin or deleted
if (rights[ADMIN]) {
acl.put(identifier, rights);
break;
} else {
if (otherAdmin(identifier)) {
acl.remove(identifier);
break;
} else {
return false;
}
}
case 2: // not allowed
return false;
case 1: // not Admin, check there remains an Admin
// Iterator namesIt = acl.keySet().iterator();
//boolean otherAdmin = false;
//while(namesIt.hasNext() && !otherAdmin) {
//String name = (String)namesIt.next();
//if (name != identifier) {
// boolean[] otherRights = (boolean[]) acl.get(name);
// otherAdmin = otherRights[ADMIN];
//}
//}
if (otherAdmin(identifier)) {
acl.put(identifier, rights);
break;
} else {
return false;
}
default: // not allowed
return false;
}
writeMailbox();
return true;
}
/**
* Check there is a person other than identifier who has Admin rights.
*/
private boolean otherAdmin(String identifier) {
Iterator namesIt = acl.keySet().iterator();
boolean result = false;
while(namesIt.hasNext() && !result) {
String name = (String)namesIt.next();
if (!name.equals(identifier)) {
boolean[] otherRights = (boolean[]) acl.get(name);
result = otherRights[ADMIN];
}
}
return result;
}
/**
* Retrieve access rights for a specific identity.
*
* @param getter String representing user attempting to get the rights,
* must be non-null and non-empty
* @param identity String representing user whose rights are being got,
* must be non-null and non-empty
* @returns String of rights usingrfc2086 syntax, empty if identity has no
* rights in this mailbox.
* @throws AccessControlException if getter does not have lookup rights for
* this mailbox (ie they should not know this mailbox exists).
* @throws AuthorizationException if implementation does not wish to expose
* ACL for this identity to this getter.
*/
public String getRights(String getter, String identity)
throws AccessControlException, AuthorizationException {
boolean[] gettersRights = (boolean[]) acl.get(getter);
if (gettersRights == null
|| (gettersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
} else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
throw new AuthorizationException(DENY_AUTH + getter);
}
boolean[] rights = (boolean[]) acl.get(identity);
if (rights == null) {
return null;
} else {
StringBuffer buf = new StringBuffer(NUMBER_OF_RIGHTS);
for (int i = 0; i<NUMBER_OF_RIGHTS; i++) {
if (rights[i]) {
buf.append(RIGHTS[i]);
}
}
return buf.toString();
}
}
/**
* Retrieves a String of one or more <identity space rights> who have
* rights in this ACL
*
* @param getter String representing user attempting to get the rights,
* must be non-null and non-empty
* @returns String of rights sets usingrfc2086 syntax
* @throws AccessControlException if getter does not have lookup rights for
* this mailbox (ie they should not know this mailbox exists).
* @throws AuthorizationException if implementation does not wish to expose
* ACL to this getter.
*/
public String getAllRights(String getter)
throws AccessControlException, AuthorizationException {
boolean[] gettersRights = (boolean[]) acl.get(getter);
if (gettersRights == null
|| (gettersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
} else if ( gettersRights[ADMIN] == false) {
throw new AuthorizationException(DENY_AUTH + getter);
}
Iterator namesIt = acl.keySet().iterator();
StringBuffer response = new StringBuffer(20*acl.size());
while(namesIt.hasNext()) {
String name = (String)namesIt.next();
response.append("<" + name + " ");
boolean[] rights = (boolean[]) acl.get(name);
for (int i = 0; i<NUMBER_OF_RIGHTS; i++) {
if (rights[i]) {
response.append(RIGHTS[i]);
}
}
response.append("> ");
}
return response.toString();
}
/**
* Retrieve rights which will always be granted to the specified identity.
*
* @param getter String representing user attempting to get the rights,
* must be non-null and non-empty
* @param identity String representing user whose rights are being got,
* must be non-null and non-empty
* @returns String of rights usingrfc2086 syntax, empty if identity has no
* guaranteed rights in this mailbox.
* @throws AccessControlException if getter does not have lookup rights for
* this mailbox (ie they should not know this mailbox exists).
* @throws AuthorizationException if implementation does not wish to expose
* ACL for this identity to this getter.
*/
public String getRequiredRights(String getter, String identity)
throws AccessControlException, AuthorizationException {
boolean[] gettersRights = (boolean[]) acl.get(getter);
if (gettersRights == null
|| (gettersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
} else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
throw new AuthorizationException(DENY_AUTH + getter);
}
return "\"\"";
}
/**
* Retrieve rights which may be granted to the specified identity.
* @param getter String representing user attempting to get the rights,
* must be non-null and non-empty
* @param identity String representing user whose rights are being got,
* must be non-null and non-empty
* @returns String of rights usingrfc2086 syntax, empty if identity has no
* guaranteed rights in this mailbox.
* @throws AccessControlException if getter does not have lookup rights for
* this mailbox (ie they should not know this mailbox exists).
* @throws AuthorizationException if implementation does not wish to expose
* ACL for this identity to this getter.
*/
public String getOptionalRights(String getter, String identity)
throws AccessControlException, AuthorizationException {
boolean[] gettersRights = (boolean[]) acl.get(getter);
if (gettersRights == null
|| (gettersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
} else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
throw new AuthorizationException(DENY_AUTH + getter);
}
return OPTIONAL_RIGHTS;
}
/**
* Helper boolean methods.
* Provided for cases where you need to check the ACL before selecting the
* mailbox.
*
* @param username String representing user
* @returns true if user has the requested right.
* &throws AccessControlException if username does not have lookup rights.
* (Except for hasLookupRights which just returns false.
*/
public boolean hasLookupRights(String username) {
boolean[] usersRights = (boolean[]) acl.get(username);
return (( usersRights == null || (usersRights[LOOKUP] == false))
? false : true);
}
public boolean hasReadRights(String username)
throws AccessControlException {
boolean[] usersRights = (boolean[]) acl.get(username);
if (usersRights == null || (usersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
}
return usersRights[READ];
}
public boolean hasKeepSeenRights(String username)
throws AccessControlException {
boolean[] usersRights = (boolean[]) acl.get(username);
if (usersRights == null || (usersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
}
return usersRights[KEEP_SEEN];
}
public boolean hasWriteRights(String username)
throws AccessControlException {
boolean[] usersRights = (boolean[]) acl.get(username);
if (usersRights == null || (usersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
}
return usersRights[WRITE];
}
public boolean hasInsertRights(String username)
throws AccessControlException {
boolean[] usersRights = (boolean[]) acl.get(username);
if (usersRights == null || (usersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
}
return usersRights[INSERT];
}
public boolean hasCreateRights(String username)
throws AccessControlException {
boolean[] usersRights = (boolean[]) acl.get(username);
if (usersRights == null || (usersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
}
return usersRights[CREATE];
}
public boolean hasDeleteRights(String username)
throws AccessControlException {
boolean[] usersRights = (boolean[]) acl.get(username);
if (usersRights == null || (usersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
}
return usersRights[DELETE];
}
public boolean hasAdminRights(String username)
throws AccessControlException {
boolean[] usersRights = (boolean[]) acl.get(username);
if (usersRights == null || (usersRights[LOOKUP] == false)) {
throw new AccessControlException(DENY_ACCESS);
}
return usersRights[ADMIN];
}
// Mailbox methods using the ACL ---------------------------
/**
* Indicates if this folder may be selected by the specified user. Requires
* user to have at least read rights. It does not indicate whether user
* can write to mailbox
*
* @param username String represnting user
* @returns boolean TRUE if specified user can Select mailbox.
* @throws AccessControlException if username does not have lookup rights
*/
public synchronized boolean isSelectable(String username)
throws AccessControlException {
return ( ! notSelectableByAnyone && hasReadRights(username) );
}
/**
* Indicates if specified user can change any flag on a permanent basis,
* except for \Recent which can never be changed by a user.
*
* @param username String represnting user
* @returns true if specified user can change all flags permanently.
*/
public synchronized boolean allFlags(String username)
throws AccessControlException {
// relies on implementation that each right implies those
// before it in list: l,r,s,w,i,p,c,d,a
return hasDeleteRights(username);
}
/**
* Indicates which flags this user can change permanently. If allFlags()
* returns true for this user, then this method must have the same return
* value as getSupportedFlags.
*
* @param username String represnting user
* @returns String a space seperated list of message flags which this user
* can set permanently
*/
public synchronized String getPermanentFlags(String username)
throws AccessControlException {
if (hasDeleteRights(username)) {
return SYSTEM_FLAGS;
} else if (hasWriteRights(username)) {
return "\\Seen \\Answered \\Flagged \\Draft";
} else if (hasKeepSeenRights(username)) {
return "\\Seen";
} else {
return "";
}
}
/**
* Provides a reference to the access control list for this mailbox.
*
* @returns the AccessControlList for this Mailbox
*/
// public ACL getACL();
/**
* Indicates state in which the mailbox will be opened by specified user.
* A return value of true indicates Read Only, false indicates Read-Write
* and an AccessControlException is thrown if user does not have read
* rights.
* <p>Implementations decide if Read Only means only lookup and read
* rights (lr) or lookup, read and keep seen rights (lrs). This may even
* vary between mailboxes.
*
* @param username String represnting user
* @returns true if specified user can only open the mailbox Read-Only.
* @throws AccessControlException if the user can not open this mailbox
* at least Read-Only.
*/
public synchronized boolean isReadOnly(String username)
throws AccessControlException {
return (! hasWriteRights(username));
}
// Message handling methods ---------------------------
/**
* Stores a message in this mailbox. User must have insert rights.
*
* @param message the MimeMessage to be stored
* @param username String represnting user
* @returns boolean true if successful
* @throws AccessControlException if username does not have lookup rights
* for this mailbox.
* @throws AuthorizationException if username has lookup rights but does
* not have insert rights.
*/
public synchronized boolean store(MimeMessage message, String username)
throws AccessControlException, AuthorizationException,
IllegalArgumentException {
if (message == null || username == null) {
getLogger().error("Null argument received in store.");
throw new IllegalArgumentException("Null argument received in store.");
}
if (!hasInsertRights(username)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to insert.");
}
SimpleMessageAttributes attrs = new SimpleMessageAttributes();
try {
setupLogger(attrs);
attrs.setAttributesFor(message);
} catch (javax.mail.MessagingException me) {
throw new RuntimeException("Exception creating SimpleMessageAttributes: " + me);
}
Flags flags = new Flags();
flags.initialize();
return store(message, username, attrs, flags);
}
/**
* Stores a message in this mailbox, using passed MessageAttributes and
* Flags. User must have insert rights.
* <br>Current implementation requires MessageAttributs to be of
* class SimpleMessageAttributes
*
* @param mail the message to be stored
* @param username String represnting user
* @param msgAttrs non-null MessageAttributes for use with this Message
* @returns boolean true if successful
* @throws AccessControlException if username does not have lookup
* rights for this mailbox.
* @throws AuthorizationException if username has lookup rights but does
* not have insert rights.
*/
public boolean store(MimeMessage message, String username,
MessageAttributes msgAttrs, Flags flags)
throws AccessControlException, AuthorizationException,
IllegalArgumentException {
if (msgAttrs == null || message == null || username == null) {
getLogger().error("Null argument received in store.");
throw new IllegalArgumentException("Null argument received in store.");
}
if (! (msgAttrs instanceof SimpleMessageAttributes)) {
getLogger().error("Wrong class for Attributes");
throw new IllegalArgumentException("Wrong class for Attributes");
}
SimpleMessageAttributes attrs = (SimpleMessageAttributes)msgAttrs;
highestUID.increase();
int newUID = highestUID.get();
attrs.setUID(newUID);
sequence.add(new Integer(newUID));
attrs.setMessageSequenceNumber(sequence.size());
BufferedOutputStream outMsg = null;
ObjectOutputStream outAttrs = null;
try {
// SK:UPDATE
path = getPath( absoluteName, owner, rootPath );
outMsg = new BufferedOutputStream( new FileOutputStream(path + File.separator + newUID + MESSAGE_EXTENSION));
message.writeTo(outMsg);
outMsg.close();
outAttrs = new ObjectOutputStream( new FileOutputStream(path + File.separator + newUID + ATTRIBUTES_EXTENSION));
outAttrs.writeObject(attrs);
outAttrs.close();
} catch(Exception e) {
getLogger().error("Error writing message to disc: " + e);
e.printStackTrace();
throw new
RuntimeException("Exception caught while storing Mail: "
+ e);
} finally {
try {
outMsg.close();
outAttrs.close();
} catch (IOException ie) {
getLogger().error("Error closing streams: " + ie);
}
}
marked = true;
if (flags.isRecent()) {
recentMessages.add(new Integer(newUID));
}
if (flags.isDeleted()) {
messagesForDeletion.add(new Integer(newUID));
}
//if (!flags.isSeen(username)) {
//If a user had no unseen messages, they do, now.
Iterator it = oldestUnseenMessage.keySet().iterator();
while (it.hasNext()) {
String user = (String)it.next();
if ( ((Integer)oldestUnseenMessage.get(user)).intValue() == -1) {
oldestUnseenMessage.put(user, new Integer(newUID));
}
}
//}
writeFlags(newUID, flags);
getLogger().info("Mail " + newUID + " written in " + absoluteName);
return true;
}
/**
* Retrieves a message given a message sequence number.
*
* @param msn the message sequence number
* @param username String represnting user
* @returns an MimeMessageWrapper object containing the message, null if no message with
* the given msn.
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have read rights.
*/
public synchronized MimeMessageWrapper retrieve(int msn, String user)
throws AccessControlException, AuthorizationException {
if (!hasReadRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to read.");
}
if (msn > sequence.size()) {
return null;
} else {
int uid = ((Integer)sequence.get(msn - 1)).intValue();
return retrieveUID(uid, user);
}
}
/**
* Retrieves a message given a unique identifier.
*
* @param uid the unique identifier of a message
* @param username String represnting user
* @returns an MimeMessageWrapper object containing the message, null if no message with
* the given msn.
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have read rights.
*/
public synchronized MimeMessageWrapper retrieveUID(int uid, String user)
throws AccessControlException, AuthorizationException {
if (!hasReadRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to read.");
}
MimeMessageWrapper response = null;
if (sequence.contains(new Integer(uid))) {
//BufferedInputStream inMsg = null;
try {
path = getPath( absoluteName, owner, rootPath );
MimeMessageFileSource source = new MimeMessageFileSource(path + File.separator + uid + MESSAGE_EXTENSION);
response = new MimeMessageWrapper(source);
// inMsg.close();
} catch(Exception e) {
getLogger().error("Error reading message from disc: " + e);
e.printStackTrace();
throw new
RuntimeException("Exception caught while retrieving Mail: "
+ e);
} //finally {
// try {
// inMsg.close();
// } catch (IOException ie) {
// getLogger().error("Error closing streams: " + ie);
// }
// }
getLogger().info("MimeMessageWrapper " + uid + " read from " + absoluteName);
return response;
} else {
return null;
}
}
/**
* Marks a message for deletion given a message sequence number.
*
* @param msn the message sequence number
* @param username String represnting user
* @returns boolean true if successful.
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have delete rights.
*/
public synchronized boolean markDeleted(int msn, String user)
throws AccessControlException, AuthorizationException {
if (!hasDeleteRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to delete.");
}
Assert.notImplemented();
//TBD
return false;
}
/**
* Marks a message for deletion given a unique identifier.
*
* @param uidunique identifier
* @param username String represnting user
* @returns boolean true if successful, false if failed including no
* message with the given uid.
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have delete rights.
*/
public synchronized boolean markDeletedUID(int uid, String user)
throws AccessControlException, AuthorizationException {
if (!hasDeleteRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to delete.");
}
Assert.notImplemented();
//TBD
return false;
}
/**
* Returns the message attributes for a message.
*
* @param msn message sequence number
* @param username String represnting user
* @returns MessageAttributes for message, null if no such message.
* Changing the MessageAttributes object must not affect the actual
* MessageAttributes.
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have delete rights.
*/
public synchronized MessageAttributes getMessageAttributes(int msn, String user)
throws AccessControlException, AuthorizationException {
if (!hasReadRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to read.");
}
System.out.println("msn: "+msn);
System.out.println("sequence.size: "+sequence.size());
if (msn > sequence.size()) {
return null;
} else {
int uid = ((Integer)sequence.get(msn - 1)).intValue();
return getMessageAttributesUID(uid, user);
}
}
/**
* Returns the message attributes for a message.
*
* @param uid unique identifier
* @param username String represnting user
* @returns MessageAttributes for message, null if no such message.
* Changing the MessageAttributes object must not affect the actual
* MessageAttributes.
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have delete rights.
*/
public synchronized MessageAttributes getMessageAttributesUID(int uid, String user)
throws AccessControlException, AuthorizationException {
if (!hasReadRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to read.");
}
System.out.println("getMessageAttributesUID()");
System.out.println("uid: "+uid);
System.out.println("user: "+user);
System.out.println("sequence.size: "+sequence.size());
SimpleMessageAttributes response = null;
if (sequence.contains(new Integer(uid))) {
System.out.println("reading from disk");
ObjectInputStream inAttrs = null;
try {
path = getPath( absoluteName, owner, rootPath );
System.out.println( "FileInputStream("+(path + File.separator + uid + ATTRIBUTES_EXTENSION));
inAttrs = new ObjectInputStream( new FileInputStream(path + File.separator + uid + ATTRIBUTES_EXTENSION));
System.out.println("inAttrs="+inAttrs);
response = (SimpleMessageAttributes)inAttrs.readObject();
System.out.println("response="+response);
if (response != null) {
System.out.println("response.parts="+response.parts);
if (response.parts != null) {
System.out.println("response.parts.len="+response.parts.length);
System.out.println("response.parts[0]="+response.parts[0]);
}
}
setupLogger(response);
} catch(Exception e) {
getLogger().error("Error reading attributes from disc: " + e);
e.printStackTrace();
throw new
RuntimeException("Exception caught while retrieving Message attributes: "
+ e);
} finally {
try {
inAttrs.close();
} catch (IOException ie) {
getLogger().error("Error closing streams: " + ie);
}
}
getLogger().info("MessageAttributes for " + uid + " read from " + absoluteName);
return response;
} else {
return null;
}
}
/**
* Updates the attributes of a message.This may be incorporated into setFlags().
*
* @param MessageAttributes of a message already in this Mailbox
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have delete rights.
*/
public boolean updateMessageAttributes(MessageAttributes attrs, String user)
throws AccessControlException, AuthorizationException {
if (!hasKeepSeenRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to store flags.");
}
int uid = attrs.getUID();
if (sequence.contains(new Integer(uid))) {
// Really, we should check whether the exact change is authorized.
ObjectOutputStream outAttrs = null;
try {
path = getPath( absoluteName, owner, rootPath );
outAttrs = new ObjectOutputStream( new FileOutputStream(path + File.separator + uid + ATTRIBUTES_EXTENSION));
outAttrs.writeObject(attrs);
outAttrs.close();
} catch(Exception e) {
getLogger().error("Error writing message to disc: " + e);
e.printStackTrace();
throw new
RuntimeException("Exception caught while storing Attributes: "
+ e);
} finally {
try {
outAttrs.close();
} catch (IOException ie) {
getLogger().error("Error closing streams: " + ie);
}
}
getLogger().info("MessageAttributes for " + uid + " written in " + absoluteName);
return true;
} else {
return false;
}
}
/**
* Get the IMAP-formatted String of flags for specified message.
*
* @param msn message sequence number for a message in this mailbox
* @param username String represnting user
* @returns flags for this message and user, null if no such message.
* @throws AccessControlException if user does not have lookup rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have read rights.
*/
public synchronized String getFlags(int msn, String user)
throws AccessControlException, AuthorizationException {
if (!hasReadRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to read.");
}
if (msn > sequence.size()) {
return null;
} else {
int uid = ((Integer)sequence.get(msn - 1)).intValue();
return getFlagsUID(uid, user);
}
}
/**
* Get the IMAP-formatted String of flags for specified message.
*
* @param uid UniqueIdentifier for a message in this mailbox
* @param username String represnting user
* @returns flags for this message and user, null if no such message.
* @throws AccessControlException if user does not have lookup rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have read rights.
*/
public synchronized String getFlagsUID(int uid, String user)
throws AccessControlException, AuthorizationException {
if (!hasReadRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to read.");
}
if (!sequence.contains(new Integer(uid))) {
System.out.println("SEQUENCENOOO");
return null;
} else {
System.out.println("FLAGSRETURNED");
Flags flags = readFlags(uid);
return flags.getFlags(user);
}
}
/**
* Updates the flags for a message.
*
* @param msn MessageSequenceNumber of a message already in this Mailbox
* @param username String represnting user
* @param request IMAP-formatted String representing requested change to
* flags.
* @returns true if succeeded, false otherwise, including no such message
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have delete rights.
*/
public synchronized boolean setFlags(int msn, String user, String request)
throws AccessControlException, AuthorizationException,
IllegalArgumentException {
if (!hasKeepSeenRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to store any flags.");
}
if (msn > sequence.size()) {
return false;
} else {
int uid = ((Integer)sequence.get(msn - 1)).intValue();
return setFlagsUID(uid, user, request);
}
}
/**
* Updates the flags for a message.
*
* @param uid Unique Identifier of a message already in this Mailbox
* @param username String represnting user
* @param request IMAP-formatted String representing requested change to
* flags.
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has lookup rights but does not
* have delete rights.
*/
public synchronized boolean setFlagsUID(int uid, String user, String request)
throws AccessControlException, AuthorizationException,
IllegalArgumentException {
if (!hasKeepSeenRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to store any flags.");
}
if ((request.toUpperCase().indexOf("DELETED") != -1) && (!hasDeleteRights(user))) { //throws AccessControlException
throw new AuthorizationException("Not authorized to delete.");
}
if (sequence.contains(new Integer(uid))) {
Flags flags = readFlags(uid);
boolean wasRecent = flags.isRecent();
boolean wasDeleted = flags.isDeleted();
boolean wasSeen = flags.isSeen(user);
if (flags.setFlags(request, user)) {
if (flags.isDeleted()) {
if (! wasDeleted) { messagesForDeletion.add(new Integer(uid)); }
}
if (flags.isSeen(user) != wasSeen) {
if (flags.isSeen(user)) {
int previousOld = ((Integer)oldestUnseenMessage.get(user)).intValue();
if (uid == previousOld) {
int newOld = findOldestUnseen(user, previousOld);
oldestUnseenMessage.put(user, (new Integer(newOld)));
}
} else { // seen flag unset
if (uid < ((Integer)oldestUnseenMessage.get(user)).intValue()) {
oldestUnseenMessage.put(user, (new Integer(uid)));
}
}
}
writeFlags(uid, flags);
getLogger().debug("Flags for message uid " + uid + " in " + absoluteName + " updated.");
return true;
} else {
return false;
}
} else {
return false;
}
}
private int findOldestUnseen(String user, int previousOld)
throws AccessControlException, AuthorizationException {
int response = 0; //indicates no unseen messages
try {
ListIterator lit = sequence.listIterator(previousOld);
boolean found = false;
while (!found && lit.hasNext() ) {
int uid = ((Integer)lit.next()).intValue();
Flags flags = readFlags(uid);
if (!flags.isSeen(user)) {
response = uid;
found = true;
}
}
}catch(Exception e) {
// (because) BUG: Do nothing. Have investigated an error on fetching sequence.listIterator(previousOld);
// with an error - but currently I don't know why :)
}finally{
return response;
}
}
private Flags readFlags(int uid) {
Flags response = null;
if (sequence.contains(new Integer(uid))) {
ObjectInputStream inFlags = null;
try {
path = getPath( absoluteName, owner, rootPath );
inFlags = new ObjectInputStream( new FileInputStream(path + File.separator + uid + FLAGS_EXTENSION));
response = (Flags)inFlags.readObject();
} catch(Exception e) {
getLogger().error("Error reading flags from disc: " + e);
e.printStackTrace();
throw new
RuntimeException("Exception caught while retrieving Message flags: "
+ e);
} finally {
try {
inFlags.close();
} catch (IOException ie) {
getLogger().error("Error closing streams: " + ie);
}
}
getLogger().info("Flags for " + uid + " read from " + absoluteName);
}
return response;
}
private boolean writeFlags(int uid, Flags flags) {
if (sequence.contains(new Integer(uid))) {
ObjectOutputStream outFlags = null;
try {
path = getPath( absoluteName, owner, rootPath );
outFlags = new ObjectOutputStream( new FileOutputStream(path + File.separator + uid + FLAGS_EXTENSION));
outFlags.writeObject(flags);
outFlags.close();
} catch(Exception e) {
getLogger().error("Error writing message to disc: " + e);
e.printStackTrace();
throw new
RuntimeException("Exception caught while storing Flags: "
+ e);
} finally {
try {
outFlags.close();
} catch (IOException ie) {
getLogger().error("Error closing streams: " + ie);
}
}
getLogger().info("Flags for " + uid + " written in " + absoluteName);
writeMailbox();
return true;
} else {
writeMailbox();
return false;
}
}
/**
* Removes all messages marked Deleted. User must have delete rights.
*
* @param username String represnting user
* @returns true if successful
* @throws AccessControlException if user does not have read rights for
* this mailbox.
* @throws AuthorizationException if user has delete rights but does not
* have delete rights.
*/
public synchronized boolean expunge(String user)
throws AccessControlException, AuthorizationException {
if (!hasDeleteRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to delete for user '" + user + "'.");
}
Iterator it = messagesForDeletion.iterator();
while (it.hasNext()) {
Integer uidObj = (Integer)it.next();
int uid = uidObj.intValue();
if (sequence.contains(uidObj)) {
try {
//SAM
try
{
MimeMessageWrapper message = retrieveUID(uid, user);
System.out.println("(before)decrementing mailboxSize ("+getName()+") = " + mailboxSize);
System.out.println("decre message.getMessageSize() = " + (int)message.getMessageSize());
mailboxSize -= (int)message.getMessageSize();
System.out.println("(after)decrementing mailboxSize ("+getName()+") = " + mailboxSize);
}
catch (MessagingException me)
{
//ignore
}
//END
path = getPath( absoluteName, owner, rootPath );
final File msgFile = new File(path + File.separator + uid + MESSAGE_EXTENSION );
msgFile.delete();
final File attrFile = new File(path + File.separator + uid + ATTRIBUTES_EXTENSION );
attrFile.delete();
//SAM
final File flagFile = new File(path + File.separator + uid + FLAGS_EXTENSION );
flagFile.delete();
//END
sequence.remove(uidObj);
} catch ( final Exception e ) {
throw new RuntimeException( "Exception caught while removing" +
" a message: " + e );
}
}
}
for (int i = 0; i < sequence.size(); i++) {
System.err.println("Message with msn " + i + " has uid " + sequence.get(i));
}
writeMailbox();
return true;
}
private void writeMailbox() {
String mailboxRecordFile = path + File.separator + MAILBOX_FILE_NAME;
ObjectOutputStream out = null;
FileOutputStream fout = null;
try {
fout = new FileOutputStream( mailboxRecordFile );
out = new ObjectOutputStream( fout );
out.writeObject(this);
out.flush();
out.close();
fout.flush();
fout.close();
} catch(Exception e) {
if (out != null) {
try {
out.close();
} catch (Exception ignored) {
}
}
if (fout != null) {
try {
fout.close();
} catch (Exception ignored) {
}
}
e.printStackTrace();
throw new
RuntimeException("Exception caught while storing Mailbox: " + e);
}
getLogger().info("FileMailbox written: " + absoluteName);
}
/**
* Lists uids of messages in mailbox indexed by MSN.
*
* @param username String represnting user
* @returns List of Integers wrapping uids of message
*/
public List listUIDs(String user) {
return new ArrayList(Collections.unmodifiableList(sequence));
}
public Set getUsersWithLookupRights() {
Set response = new HashSet();
Iterator it = acl.keySet().iterator();
while (it.hasNext()) {
String user = (String) it.next();
boolean[] rights = (boolean[]) acl.get(user);
if (rights[LOOKUP] == true) {
response.add(user);
}
}
return response;
}
public Set getUsersWithReadRights() {
Set response = new HashSet();
Iterator it = acl.keySet().iterator();
while (it.hasNext()) {
String user = (String) it.next();
boolean[] rights = (boolean[]) acl.get(user);
if (rights[READ] == true) {
response.add(user);
}
}
return response;
}
public Map getUnseenByUser() {
Map response = new HashMap();
Iterator it = oldestUnseenMessage.keySet().iterator();
while (it.hasNext()) {
String user = (String) it.next();
Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
int oldUID = uidObj.intValue();
if (oldUID == 0) {
response.put(user, uidObj);
} else {
int count = 0;
ListIterator lit
= sequence.listIterator(sequence.indexOf(uidObj));
while (lit.hasNext() ) {
int uid = ((Integer)lit.next()).intValue();
Flags flags = readFlags(uid);
if (!flags.isSeen(user)) {
count ++;
}
}
response.put(user, new Integer(count));
}
}
return response;
}
public InternetHeaders getInternetHeaders(int msn, String user)
throws AccessControlException, AuthorizationException {
if (!hasReadRights(user)) { //throws AccessControlException
throw new AuthorizationException("Not authorized to read.");
}
if (msn > sequence.size()) {
return null;
} else {
int uid = ((Integer)sequence.get(msn - 1)).intValue();
return getInternetHeadersUID(uid, user);
}
}
public InternetHeaders getInternetHeadersUID(int uid, String user)
throws AccessControlException, AuthorizationException {
InternetHeaders response = null;
if (sequence.contains(new Integer(uid))) {
BufferedInputStream inMsg = null;
try {
inMsg = new BufferedInputStream( new FileInputStream(path + File.separator + uid + MESSAGE_EXTENSION));
response = new InternetHeaders(inMsg);
inMsg.close();
} catch(Exception e) {
getLogger().error("Error reading headers of message from disc: " + e);
e.printStackTrace();
throw new
RuntimeException("Exception caughtt while retrieving InternetHeaders: " + e);
} finally {
try {
inMsg.close();
} catch (IOException ie) {
getLogger().error("Error closing streams: " + ie);
}
}
getLogger().info("InternetHeaders for message " + uid + " read from "
+ absoluteName);
return response;
} else {
return null;
}
}
/**
* Returns true if the named user is subscribed to this Mailbox.
*/
public boolean isSubscribed( String userName )
{
return subscribedUsers.contains( userName.toLowerCase() );
}
/**
* Subscribes a user to this Mailbox.
*/
public void subscribe( String userName )
{
subscribedUsers.add( userName.toLowerCase() );
}
/**
* Unsubscrive a user from this Mailbox.
*/
public void unsubscribe( String userName )
{
subscribedUsers.remove( userName.toLowerCase() );
}
}
1.1 jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands/CommandFetch.java
Index: CommandFetch.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.imapserver;
import org.apache.james.AccessControlException;
import org.apache.james.AuthorizationException;
import org.apache.james.core.MimeMessageWrapper;
import org.apache.james.imapserver.commands.ImapCommand;
import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.*;
/**
* Implements the IMAP FETCH command for a given ImapRequestImpl.
*
* References: rfc 2060, rfc 2193, rfc 2221
* @author <a href="mailto:sascha@kulawik.de">Sascha Kulawik</a>
* @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
* @version 0.2 on 04 Aug 2002
*/
public class CommandFetch
extends BaseCommand implements ImapCommand
{
//mainly to switch on stack traces and catch responses;
private static final boolean DEEP_DEBUG = true;
private static final String OK = "OK";
private static final String NO = "NO";
private static final String BAD = "BAD";
private static final String UNTAGGED = "*";
private static final String SP = " ";
private StringTokenizer commandLine;
private boolean useUIDs;
private ACLMailbox currentMailbox;
private String commandRaw;
private PrintWriter out;
private OutputStream outs;
private String tag;
private String user;
private SingleThreadedConnectionHandler caller;
private String currentFolder;
public boolean validForState( ImapSessionState state )
{
return ( state == ImapSessionState.SELECTED );
}
public boolean process( ImapRequest request, ImapSession session )
{
setRequest( request );
StringTokenizer txt = request.getCommandLine();
/* System.out.println("CommandFetch.process: #args="+txt.countTokens());
while (txt.hasMoreTokens()) {
System.out.println("CommandFetch.process: arg='"+txt.nextToken()+"'");
}
*/
// ((ImapRequestImpl)request).setCommandLine(new java.util.StringTokenizer(request.getCommandRaw()));
if ( request.arguments() < 2 ) {
session.badResponse( "#args="+request.arguments()+" '"+request.getCommandLine().nextToken()+"', '"+request.getCommandLine().nextToken()+"' Command should be <tag> <FETCH> <message set> <message data item names>" );
return true;
}
service();
return true;
}
/**
* Debugging method - will probably disappear
*/
public void setRequest(ImapRequest request) {
commandLine = request.getCommandLine();
useUIDs = request.useUIDs();
currentMailbox = request.getCurrentMailbox();
System.out.println("currentMailbox="+((currentMailbox!=null)?currentMailbox.getClass().getName():"null"));
commandRaw = request.getCommandRaw();
tag = request.getTag();
currentFolder = request.getCurrentFolder();
caller = request.getCaller();
out = caller.getPrintWriter();
outs = caller.getOutputStream();
user = caller.getUser();
}
/**
* Implements IMAP fetch commands given an ImapRequestImpl.
* This implementation attempts to satisfy the fetch command with the
* smallest objects deserialized from storage.
* <p>Warning - maybecome service(ImapRequestImpl request)
* <p>Not yet complete - no partial (octet-counted or sub-parts) fetches.
*/
public void service() {
// decode the message set
List set;
List uidsList = null;
String setArg = commandLine.nextToken();
if (useUIDs) {
uidsList = currentMailbox.listUIDs(user);
set = decodeUIDSet(setArg, uidsList);
} else {
set = decodeSet(setArg, currentMailbox.getExists());
}
if (DEEP_DEBUG) {
getLogger().debug("Fetching message set of size: " + set.size());
}
String firstFetchArg = commandLine.nextToken();
int pos = commandRaw.indexOf(firstFetchArg);
//int pos = commandRaw.indexOf(setArg) + setArg.length() + 1;
String fetchAttrsRaw = null;
if (firstFetchArg.startsWith("(")) { //paranthesised fetch attrs
fetchAttrsRaw = commandRaw.substring(pos + 1, commandRaw.lastIndexOf(")"));
} else {
fetchAttrsRaw = commandRaw.substring(pos);
}
if (DEEP_DEBUG) {
System.out.println("Found fetchAttrsRaw: " + fetchAttrsRaw);
getLogger().debug("Found fetchAttrsRaw: " + fetchAttrsRaw);
}
// decode the fetch attributes
List fetchAttrs = new ArrayList();
StringTokenizer fetchTokens = new StringTokenizer(fetchAttrsRaw);
while (fetchTokens.hasMoreTokens()) {
String attr = fetchTokens.nextToken();
if (attr.indexOf("(") == -1 ) { //not the start of a fields list
fetchAttrs.add(attr);
} else {
StringBuffer attrWithFields = new StringBuffer();
attrWithFields.append(fetchAttrs.remove(fetchAttrs.size() -1));
attrWithFields.append(" " + attr);
boolean endOfFields = false;
while (! endOfFields && fetchTokens.hasMoreTokens()) {
String field = fetchTokens.nextToken();
attrWithFields.append(" " + field);
if (field.indexOf(")") != -1) {
endOfFields = true;
}
}
fetchAttrs.add(attrWithFields.toString());
}
}
fetchAttrs = convertMacroCommands( fetchAttrs );
try {
for (int i = 0; i < set.size(); i++) {
Integer uidObject = null;
int uid = 0;
int msn = 0;
if (useUIDs) {
System.out.println("USE UIDS");
uidObject = (Integer)set.get(i);
uid = uidObject.intValue();
msn = uidsList.indexOf(uidObject) + 1;
} else {
msn = ((Integer)set.get(i)).intValue();
}
MessageAttributes attrs = null;
String flags = null;
//EnhancedMimeMessage msg = null;
MimeMessageWrapper msg = null;
String response = UNTAGGED + SP + msn + SP + "FETCH (";
boolean responseAdded = false;
Iterator it = fetchAttrs.iterator();
while(it.hasNext()) {
String arg = (String) it.next();
// commands that only need flags object
if (arg.equalsIgnoreCase("FLAGS")) {
if (flags == null) {
if (useUIDs) {
System.out.println("TRIING UIDFLAGS"+uid);
flags = currentMailbox.getFlagsUID(uid, user);
} else {
System.out.println("TRIING MSNFLAGS"+msn);
flags = currentMailbox.getFlags(msn, user);
}
}
if (flags == null) { // bad
//out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message flags.");
//System.out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message flags.");
//return;
}
if (responseAdded) {
response += SP + "FLAGS " + flags ;
} else {
response += "FLAGS " + flags ;
responseAdded = true;
}
}
// command that only need MessageAttributes object
else if (arg.equalsIgnoreCase("INTERNALDATE")) {
System.out.println("Starting INTERNALDATE");
if (attrs == null) {
if (useUIDs) {
attrs = currentMailbox.getMessageAttributesUID(uid, user);
} else {
attrs = currentMailbox.getMessageAttributes(msn, user);
}
}
if (attrs == null) { // bad
out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message attributes.");
System.out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message attributes.");
getLogger().error("Retrieved null attributes for msn:" + msn);
return;
}
if (responseAdded) {
response += SP + "INTERNALDATE \""
+ attrs.getInternalDateAsString() + "\"" ;
} else {
response += "INTERNALDATE \""
+ attrs.getInternalDateAsString() + "\"" ;
responseAdded = true;
}
} else if (arg.equalsIgnoreCase("RFC822.SIZE")) {
System.out.println("Starting RFC822.SIZE");
if (attrs == null) {
if (useUIDs) {
attrs = currentMailbox.getMessageAttributesUID(uid, user);
} else {
attrs = currentMailbox.getMessageAttributes(msn, user);
}
}
if (attrs == null) { // bad
out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message attributes.");
System.out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message attributes.");
getLogger().error("Retrieved null attributes for msn:" + msn);
return;
}
if (responseAdded) {
response += SP + "RFC822.SIZE " + attrs.getSize();
} else {
response += "RFC822.SIZE " + attrs.getSize();
responseAdded = true;
}
} else if (arg.equalsIgnoreCase("ENVELOPE")) {
System.out.println("Starting ENVELOPE");
if (attrs == null) {
if (useUIDs) {
attrs = currentMailbox.getMessageAttributesUID(uid, user);
} else {
attrs = currentMailbox.getMessageAttributes(msn, user);
}
}
if (attrs == null) { // bad
out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message attributes.");
System.out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message attributes.");
getLogger().error("Retrieved null attributes for msn:" + msn);
return;
}
if (responseAdded) {
response += SP + "ENVELOPE " + attrs.getEnvelope();
} else {
response += "ENVELOPE " + attrs.getEnvelope();
responseAdded = true;
}
} else if (arg.equalsIgnoreCase("BODY")) {
System.out.println("CommandFetch BODY start");
if (attrs == null) {
System.out.println("CommandFetch BODY fetching attrs");
if (useUIDs) {
attrs = currentMailbox.getMessageAttributesUID(uid, user);
System.out.println("currentMailbox.getMessageAttributesUID("+uid+","+user+")");
} else {
attrs = currentMailbox.getMessageAttributes(msn, user);
System.out.println("currentMailbox.getMessageAttributes("+msn+","+user+")");
}
System.out.println("attrs="+((attrs!=null)?attrs.getClass().getName():"null"));
}
System.out.println("CommandFetch BODY attrs="+attrs);
System.out.println("CommandFetch BODY attrs.getUID: "+attrs.getUID());
if (attrs == null) { // bad
out.println(tag + SP + msn + SP + NO + "Error retrieving message attributes.");
getLogger().error("Retrieved null attributes for msn:" + msn);
return;
}
if (responseAdded) {
response += SP + "BODY " + attrs.getBodyStructure();
} else {
response += "BODY " + attrs.getBodyStructure();
responseAdded = true;
}
} else if (arg.equalsIgnoreCase("BODYSTRUCTURE")) {
System.out.println("Starting BODYSTRUCTURE");
if (attrs == null) {
if (useUIDs) {
attrs = currentMailbox.getMessageAttributesUID(uid, user);
} else {
attrs = currentMailbox.getMessageAttributes(msn, user);
}
}
if (attrs == null) { // bad
out.println(tag + SP + msn + SP + NO + "Error retrieving message attributes.");
getLogger().error("Retrieved null attributes for msn:" + msn);
return;
}
if (responseAdded) {
response += SP + "BODYSTRUCTURE "+ attrs.getBodyStructure();
} else {
response += "BODYSTRUCTURE "+ attrs.getBodyStructure();
responseAdded = true;
}
} else if (arg.equalsIgnoreCase("UID")) {
System.out.println("CommandFetch UID start");
if (!useUIDs || fetchAttrs.size() == 1){
System.out.println("CommandFetch.!useUIDs");
if (attrs == null) {
System.out.println("CommandFetch UID fetching attrs: "+attrs);
attrs = currentMailbox.getMessageAttributes(msn, user);
}
uid = attrs.getUID();
System.out.println("CommandFetch UID attrs: "+attrs);
System.out.println("CommandFetch UID attrs.getUID: "+attrs.getUID());
if (attrs == null) { // bad
out.println(tag + SP + msn + SP + NO + "Error retrieving message attributes.");
getLogger().error("Retrieved null attributes for msn:" + msn);
return;
}
System.out.println("CommandFetch UID printing UID: "+uid);
if (responseAdded) {
response += SP + "UID "+ uid;
} else {
response += "UID "+ uid;
responseAdded = true;
}
} // don't duplicate on UID FETCH requests
System.out.println("CommandFetch UID end");
}
// commands that can be satisifed with just top-level headers of message and flags
else if (arg.equalsIgnoreCase("BODY[HEADER]")
|| arg.equalsIgnoreCase("BODY.PEEK[HEADER]")
|| "RFC822.HEADER".equalsIgnoreCase(arg)) {
System.out.println("Starting BODY[HEADER]");
if (responseAdded) { // unlikely
if (useUIDs) {
response += " UID " + uid + ")";
} else {
response += ")";
}
System.out.println(response);
out.println(response);
getLogger().debug("Sending: " + response);
}
InternetHeaders headers = null;
if (useUIDs) {
headers = currentMailbox.getInternetHeadersUID(uid, user);
} else {
headers = currentMailbox.getInternetHeaders(msn, user);
}
if (headers == null) { // bad
System.out.println(tag + SP + msn + SP + NO + "Error retrieving message1.");
out.println(tag + SP + msn + SP + NO + "Error retrieving message1.");
getLogger().error("Retrieved null headers for msn:" + msn);
return;
}
if (flags == null) {
if (useUIDs) {
flags = currentMailbox.getFlagsUID(uid, user);
} else {
flags = currentMailbox.getFlags(msn, user);
}
}
response = UNTAGGED + SP + msn + SP + "FETCH (";
response += "BODY[HEADER] ";
Enumeration enum = headers.getAllHeaderLines();
List lines = new ArrayList();
int count = 0;
while (enum.hasMoreElements()) {
String line = (String)enum.nextElement();
count += line.length() + 2;
lines.add(line);
}
response += "{" + (count + 2) + "}";
out.println(response);
System.out.println(response);
getLogger().debug("Sending: " + response);
Iterator lit = lines.iterator();
while (lit.hasNext()) {
String line = (String)lit.next();
out.println(line);
System.out.println(line);
getLogger().debug("Sending: " + line);
}
out.println();
System.out.println();
getLogger().debug("Sending blank line");
if (useUIDs) {
out.println( " UID " + uid + ")");
System.out.println( " UID " + uid + ")");
getLogger().debug("Sending: UID " + uid + ")");
} else {
out.println( ")" );
System.out.println( ")" );
getLogger().debug("Sending: )");
}
if (! arg.equalsIgnoreCase("BODY.PEEK[HEADER]")) {
try { // around setFlags()
if (flags.indexOf("Seen") == -1 ) {
String newflags;
if (useUIDs) {
currentMailbox.setFlagsUID(uid, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlagsUID(uid, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
} else {
currentMailbox.setFlags(msn, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlags(msn, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
}
}
} catch (AccessControlException ace) {
getLogger().error("Exception storing flags for message: " + ace);
} catch (AuthorizationException aze) {
getLogger().error("Exception storing flags for message: " + aze);
} catch (Exception e) {
getLogger().error("Unanticipated exception storing flags for message: " + e);
}
}
response = UNTAGGED + SP + msn + SP + "FETCH (";
responseAdded = false;
} else if (arg.toUpperCase().startsWith("BODY[HEADER.FIELDS")
|| arg.toUpperCase().startsWith("BODY.PEEK[HEADER.FIELDS")
|| arg.toUpperCase().startsWith("(BODY.PEEK[HEADER.FIELDS")){
System.out.println("Starting BODY[HEADER.FIELDS]");
if (responseAdded) {
if (useUIDs) {
response += " UID " + uid + ")";
} else {
response += ")";
}
out.println(response);
System.out.println(response);
getLogger().debug("Sending: " + response);
}
InternetHeaders headers = null;
if (useUIDs) {
headers = currentMailbox.getInternetHeadersUID(uid, user);
} else {
headers = currentMailbox.getInternetHeaders(msn, user);
}
if (headers == null) { // bad
out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message2.");
System.out.println(tag + SP + msn + SP + NO + SP + "Error retrieving message2.");
getLogger().error("Retrieved null headers for msn:" + msn);
return;
}
if (flags == null) {
if (useUIDs) {
flags = currentMailbox.getFlagsUID(uid, user);
} else {
flags = currentMailbox.getFlags(msn, user);
}
}
boolean not = (commandRaw.toUpperCase().indexOf("HEADER.FIELDS.NOT") != -1);
boolean peek = (commandRaw.toUpperCase().indexOf("PEEK") != -1);
response = UNTAGGED + SP + msn + SP + "FETCH (BODY" ;
if (peek) {response += ".PEEK";}
if (not) {
response += "[HEADER.FIELDS.NOT (";
} else {
response += "[HEADER.FIELDS (";
}
responseAdded = false;
//int h = commandRaw.indexOf("[");
int left = arg.indexOf("(");
int right = arg.indexOf(")");
String fieldsRequested = arg.substring(left + 1, right);
response += fieldsRequested + ")] ";
ArrayList fields = new ArrayList();
if (fieldsRequested.indexOf(" ") == -1) { //only one field
fields.add(fieldsRequested);
} else {
StringTokenizer tok = new StringTokenizer(fieldsRequested);
while (tok.hasMoreTokens()) {
fields.add((String)tok.nextToken());
}
}
Iterator it2 = fields.iterator();
while (it2.hasNext()) {
getLogger().debug("request for field: " + (String)it2.next());
}
String[] names = (String[])fields.toArray(new String[fields.size()]);
Enumeration enum = null;
if (not) {
enum = headers.getNonMatchingHeaderLines(names);
} else {
enum = headers.getMatchingHeaderLines(names);
}
List lines = new ArrayList();
int count = 0;
while (enum.hasMoreElements()) {
String line = (String)enum.nextElement();
count += line.length() + 2;
lines.add(line);
}
response += "{" + (count + 2) + "}";
out.println(response);
System.out.println(response);
getLogger().debug("Sending: " + response);
Iterator lit = lines.iterator();
while (lit.hasNext()) {
String line = (String)lit.next();
out.println(line);
System.out.println(line);
getLogger().debug("Sending: " + line);
}
out.println();
System.out.println();
if (useUIDs) {
out.println( " UID " + uid + ")");
System.out.println( " UID " + uid + ")");
} else {
out.println(")");
System.out.println(")");
}
if (! peek) {
if (flags.indexOf("Seen") == -1 ) {
try {
String newflags;
if (useUIDs) {
currentMailbox.setFlagsUID(uid, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlagsUID(uid, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
} else {
currentMailbox.setFlags(msn, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlags(msn, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
}
} catch (AccessControlException ace) {
getLogger().error("Exception storing flags for message: " + ace);
} catch (AuthorizationException aze) {
getLogger().error("Exception storing flags for message: " + aze);
} catch (Exception e) {
getLogger().error("Unanticipated exception storing flags for message: " + e);
}
}
}
response = UNTAGGED + SP + msn + SP + "FETCH (";
responseAdded = false;
}
// Calls to underlying MimeMessage
else if (arg.equalsIgnoreCase("RFC822")
|| arg.equalsIgnoreCase("BODY[]")
|| arg.equalsIgnoreCase("BODY.PEEK[]")) {
System.out.println("Starting BODY[]");
if (responseAdded) { // unlikely
if (useUIDs) {
response += " UID " + uid + ")";
} else {
response += ")";
}
out.println(response);
System.out.println(response);
}
if (msg == null) { // probably
if (useUIDs) {
msg = currentMailbox.retrieveUID(uid, user);
} else {
msg = currentMailbox.retrieve(msn, user);
}
}
if (flags == null) {
if (useUIDs) {
flags = currentMailbox.getFlagsUID(uid, user);
} else {
flags = currentMailbox.getFlags(msn, user);
}
}
if (msg == null) { // bad
out.println(tag + SP + msn + SP + BAD + "Error retrieving message3.");
System.out.println(tag + SP + msn + SP + BAD + "Error retrieving message3.");
getLogger().error("Retrieved null message");
return;
}
try {
long size = msg.getMessageSize();
if (arg.equalsIgnoreCase("RFC822")) {
out.println(UNTAGGED + SP + msn + SP + "FETCH ( RFC822 {" + size + "}");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH ( RFC822 {" + size + "}");
} else {
out.println(UNTAGGED + SP + msn + SP + "FETCH ( BODY[] {" + size + "}");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH ( BODY[] {" + size + "}");
}
msg.writeTo(outs);
if (useUIDs) {
out.println(" UID " + uid + ")");
System.out.println(" UID " + uid + ")");
} else {
out.println(")");
System.out.println(")");
}
if (! arg.equalsIgnoreCase("BODY.PEEK[]")) {
if (flags.indexOf("Seen") == -1 ) {
String newflags;
if (useUIDs) {
currentMailbox.setFlagsUID(uid, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlagsUID(uid, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
} else {
currentMailbox.setFlags(msn, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlags(msn, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
}
}
}
} catch (MessagingException me) {
out.println(UNTAGGED + SP + NO + SP + "Error retrieving message4");
System.out.println(UNTAGGED + SP + NO + SP + "Error retrieving message4");
getLogger().error("Exception retrieving message: " + me);
} catch (IOException ioe) {
out.println(UNTAGGED + SP + NO + SP + "Error retrieving message5");
System.out.println(UNTAGGED + SP + NO + SP + "Error retrieving message5");
getLogger().error("Exception sending message: " + ioe);
} catch (Exception e) {
out.println(UNTAGGED + SP + NO + SP + "Error retrieving message6");
System.out.println(UNTAGGED + SP + NO + SP + "Error retrieving message6");
getLogger().error("Unanticipated exception retrieving message: " + e);
}
response = UNTAGGED + SP + msn + SP + "FETCH (";
responseAdded = false;
} else if (arg.equalsIgnoreCase("RFC822.TEXT")
|| arg.equalsIgnoreCase("BODY[TEXT]")
|| arg.equalsIgnoreCase("BODY.PEEK[TEXT]")) {
System.out.println("Starting BODY[TEXT]");
if (responseAdded) { // unlikely
if (useUIDs) {
response += " UID " + uid + ")";
} else {
response += ")";
}
out.println(response);
System.out.println(response);
}
if (msg == null) { // probably
if (useUIDs) {
msg = currentMailbox.retrieveUID(uid, user);
} else {
msg = currentMailbox.retrieve(msn, user);
}
}
if (flags == null) {
if (useUIDs) {
flags = currentMailbox.getFlagsUID(uid, user);
} else {
flags = currentMailbox.getFlags(msn, user);
}
}
if (msg == null) { // bad
out.println(tag + SP + msn + SP + NO + "Error retrieving message7.");
System.out.println(tag + SP + msn + SP + NO + "Error retrieving message7.");
getLogger().error("Retrieved null message");
return;
}
try {
int size = msg.getSize();
if (arg.equalsIgnoreCase("RFC822.TEXT")) {
out.println(UNTAGGED + SP + msn + SP + "FETCH ( RFC822.TEXT {" + size + "}");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH ( RFC822.TEXT {" + size + "}");
} else {
out.println(UNTAGGED + SP + msn + SP + "FETCH ( BODY[TEXT] {" + size + "}");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH ( BODY[TEXT] {" + size + "}");
}
msg.writeContentTo(outs);
if (useUIDs) {
out.println( " UID " + uid + ")");
System.out.println( " UID " + uid + ")");
} else {
out.println(")");
System.out.println(")");
}
if (! arg.equalsIgnoreCase("BODY.PEEK[TEXT]")) {
if (flags.indexOf("Seen") == -1 ) {
String newflags;
if (useUIDs) {
currentMailbox.setFlagsUID(uid, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlagsUID(uid, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + " UID " + uid +")");
} else {
currentMailbox.setFlags(msn, user, "+flags (\\Seen)");
newflags = currentMailbox.getFlags(msn, user);
out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
System.out.println(UNTAGGED + SP + msn + SP + "FETCH (FLAGS "
+ newflags + ")");
}
}
}
} catch (MessagingException me) {
out.println(UNTAGGED + SP + NO + SP + "Error retrieving message8:"+me);
System.out.println(UNTAGGED + SP + NO + SP + "Error retrieving message8:"+me);
me.printStackTrace();
getLogger().error("Exception retrieving message: " + me);
} catch (IOException ioe) {
out.println(UNTAGGED + SP + NO + SP + "Error retrieving message9");
System.out.println(UNTAGGED + SP + NO + SP + "Error retrieving message9");
getLogger().error("Exception sending message: " + ioe);
} catch (Exception e) {
out.println(UNTAGGED + SP + NO + SP + "Error retrieving message10");
System.out.println(UNTAGGED + SP + NO + SP + "Error retrieving message10");
getLogger().error("Unanticipated exception retrieving message: " + e);
}
response = UNTAGGED + SP + msn + SP + "FETCH (";
responseAdded = false;
} else { //unrecognised or not yet implemented
if (responseAdded) {
if (useUIDs) {
response += " UID " + uid + ")";
} else {
response += ")";
}
out.println(response);
System.out.println(response);
}
out.println(tag + SP + NO + SP
+ "FETCH attribute not recognized");
System.out.println(tag + SP + NO + SP
+ "FETCH attribute not recognized");
getLogger().error("Received: " + arg + " as argument to fetch");
return;
}
} // end while loop
if (responseAdded) {
if (useUIDs) {
response += " UID " + uid + ")";
} else {
response += ")";
}
out.println(response);
System.out.println(response);
}
} // end for loop
out.println(tag + SP + OK + SP + "FETCH completed");
System.out.println(tag + SP + OK + SP + "FETCH completed");
caller.checkSize();
return;
} catch (AccessControlException ace) {
out.println(tag + SP + NO + SP + "No such mailbox");
System.out.println(tag + SP + NO + SP + "No such mailbox");
caller.logACE(ace);
return;
} catch (AuthorizationException aze) {
out.println(tag + SP + NO + SP
+ "You do not have the rights to read from mailbox: " + currentFolder);
System.out.println(tag + SP + NO + SP
+ "You do not have the rights to read from mailbox: " + currentFolder);
caller.logAZE(aze);
return ;
} catch (Exception e) {
out.println(tag + SP + NO + SP
+ "Unknown server error.");
System.out.println(tag + SP + NO + SP
+ "Unknown server error.");
getLogger().error("Exception expunging mailbox " + currentFolder + " by user " + user + " was : " + e);
if (DEEP_DEBUG) {e.printStackTrace();}
return;
}
}
private List convertMacroCommands( List fetchAttributes )
{
List convertedAttributes = new ArrayList();
// convert macro fetch commands to basic commands
Iterator iter = fetchAttributes.iterator();
while ( iter.hasNext() ) {
String arg = (String)iter.next();
if (arg.equalsIgnoreCase("FAST")) {
convertedAttributes.add("FLAGS");
convertedAttributes.add("INTERNALDATE");
convertedAttributes.add("RFC822.SIZE");
} else if (arg.equalsIgnoreCase("ALL")) {
convertedAttributes.add("FLAGS");
convertedAttributes.add("INTERNALDATE");
convertedAttributes.add("RFC822.SIZE");
convertedAttributes.add("ENVELOPE");
} else if (arg.equalsIgnoreCase("FULL")) {
convertedAttributes.add("FLAGS");
convertedAttributes.add("INTERNALDATE");
convertedAttributes.add("RFC822.SIZE");
convertedAttributes.add("ENVELOPE");
convertedAttributes.add("BODY");
}
else {
convertedAttributes.add( arg );
}
getLogger().debug("Found convertedAttributes: " + arg);
}
return convertedAttributes;
}
}
1.1 jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands/HighestUID.java
Index: HighestUID.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.imapserver;
/**
* Reference: RFC 2060
* @author <a href="mailto:s@rapi.com">Stephan Schiessling</a>
* @version 0.1 on 15 Aug 2002
*/
public interface HighestUID {
int get();
void increase();
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>