| /** |
| * |
| * Copyright 2003-2004 The Apache Software Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package javax.mail; |
| |
| import java.io.Serializable; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| /** |
| * Representation of flags that may be associated with a message. |
| * Flags can either be system flags, defined by the {@link Flags.Flag Flag} inner class, |
| * or user-defined flags defined by a String. The system flags represent those expected |
| * to be provided by most folder systems; user-defined flags allow for additional flags |
| * on a per-provider basis. |
| * <p/> |
| * This class is Serializable but compatibility is not guaranteed across releases. |
| * |
| * @version $Rev$ $Date$ |
| */ |
| public class Flags implements Cloneable, Serializable { |
| public static final class Flag { |
| /** |
| * Flag that indicates that the message has been replied to; has a bit value of 1. |
| */ |
| public static final Flag ANSWERED = new Flag(1); |
| /** |
| * Flag that indicates that the message has been marked for deletion and |
| * should be removed on a subsequent expunge operation; has a bit value of 2. |
| */ |
| public static final Flag DELETED = new Flag(2); |
| /** |
| * Flag that indicates that the message is a draft; has a bit value of 4. |
| */ |
| public static final Flag DRAFT = new Flag(4); |
| /** |
| * Flag that indicates that the message has been flagged; has a bit value of 8. |
| */ |
| public static final Flag FLAGGED = new Flag(8); |
| /** |
| * Flag that indicates that the message has been delivered since the last time |
| * this folder was opened; has a bit value of 16. |
| */ |
| public static final Flag RECENT = new Flag(16); |
| /** |
| * Flag that indicates that the message has been viewed; has a bit value of 32. |
| * This flag is set by the {@link Message#getInputStream()} and {@link Message#getContent()} |
| * methods. |
| */ |
| public static final Flag SEEN = new Flag(32); |
| /** |
| * Flags that indicates if this folder supports user-defined flags; has a bit value of 0x80000000. |
| */ |
| public static final Flag USER = new Flag(0x80000000); |
| |
| private final int mask; |
| |
| private Flag(int mask) { |
| this.mask = mask; |
| } |
| } |
| |
| // the Serialized form of this class required the following two fields to be persisted |
| // this leads to a specific type of implementation |
| private int system_flags; |
| private final Hashtable user_flags; |
| |
| /** |
| * Construct a Flags instance with no flags set. |
| */ |
| public Flags() { |
| user_flags = new Hashtable(); |
| } |
| |
| /** |
| * Construct a Flags instance with a supplied system flag set. |
| * @param flag the system flag to set |
| */ |
| public Flags(Flag flag) { |
| system_flags = flag.mask; |
| user_flags = new Hashtable(); |
| } |
| |
| /** |
| * Construct a Flags instance with a same flags set. |
| * @param flags the instance to copy |
| */ |
| public Flags(Flags flags) { |
| system_flags = flags.system_flags; |
| user_flags = new Hashtable(flags.user_flags); |
| } |
| |
| /** |
| * Construct a Flags instance with the supplied user flags set. |
| * Question: should this automatically set the USER system flag? |
| * @param name the user flag to set |
| */ |
| public Flags(String name) { |
| user_flags = new Hashtable(); |
| user_flags.put(name.toLowerCase(), name); |
| } |
| |
| /** |
| * Set a system flag. |
| * @param flag the system flag to set |
| */ |
| public void add(Flag flag) { |
| system_flags |= flag.mask; |
| } |
| |
| /** |
| * Set all system and user flags from the supplied Flags. |
| * Question: do we need to check compatibility of USER flags? |
| * @param flags the Flags to add |
| */ |
| public void add(Flags flags) { |
| system_flags |= flags.system_flags; |
| user_flags.putAll(flags.user_flags); |
| } |
| |
| /** |
| * Set a user flag. |
| * Question: should this fail if the USER system flag is not set? |
| * @param name the user flag to set |
| */ |
| public void add(String name) { |
| user_flags.put(name.toLowerCase(), name); |
| } |
| |
| /** |
| * Return a copy of this instance. |
| * @return a copy of this instance |
| */ |
| public Object clone() { |
| return new Flags(this); |
| } |
| |
| /** |
| * See if the supplied system flags are set |
| * @param flag the system flags to check for |
| * @return true if the flags are set |
| */ |
| public boolean contains(Flag flag) { |
| return (system_flags & flag.mask) != 0; |
| } |
| |
| /** |
| * See if all of the supplied Flags are set |
| * @param flags the flags to check for |
| * @return true if all the supplied system and user flags are set |
| */ |
| public boolean contains(Flags flags) { |
| return ((system_flags & flags.system_flags) == flags.system_flags) |
| && user_flags.keySet().containsAll(flags.user_flags.keySet()); |
| } |
| |
| /** |
| * See if the supplied user flag is set |
| * @param name the user flag to check for |
| * @return true if the flag is set |
| */ |
| public boolean contains(String name) { |
| return user_flags.containsKey(name.toLowerCase()); |
| } |
| |
| /** |
| * Equality is defined as true if the other object is a instanceof Flags with the |
| * same system and user flags set (using a case-insensitive name comparison for user flags). |
| * @param other the instance to compare against |
| * @return true if the two instance are the same |
| */ |
| public boolean equals(Object other) { |
| if (other == this) return true; |
| if (other instanceof Flags == false) return false; |
| final Flags flags = (Flags) other; |
| return system_flags == flags.system_flags && user_flags.keySet().equals(flags.user_flags.keySet()); |
| } |
| |
| /** |
| * Calculate a hashCode for this instance |
| * @return a hashCode for this instance |
| */ |
| public int hashCode() { |
| return system_flags ^ user_flags.keySet().hashCode(); |
| } |
| |
| /** |
| * Return a list of {@link Flags.Flag Flags} containing the system flags that have been set |
| * @return the system flags that have been set |
| */ |
| public Flag[] getSystemFlags() { |
| // assumption: it is quicker to calculate the size than it is to reallocate the array |
| int size = 0; |
| if ((system_flags & Flag.ANSWERED.mask) != 0) size += 1; |
| if ((system_flags & Flag.DELETED.mask) != 0) size += 1; |
| if ((system_flags & Flag.DRAFT.mask) != 0) size += 1; |
| if ((system_flags & Flag.FLAGGED.mask) != 0) size += 1; |
| if ((system_flags & Flag.RECENT.mask) != 0) size += 1; |
| if ((system_flags & Flag.SEEN.mask) != 0) size += 1; |
| if ((system_flags & Flag.USER.mask) != 0) size += 1; |
| Flag[] result = new Flag[size]; |
| if ((system_flags & Flag.USER.mask) != 0) result[--size] = Flag.USER; |
| if ((system_flags & Flag.SEEN.mask) != 0) result[--size] = Flag.SEEN; |
| if ((system_flags & Flag.RECENT.mask) != 0) result[--size] = Flag.RECENT; |
| if ((system_flags & Flag.FLAGGED.mask) != 0) result[--size] = Flag.FLAGGED; |
| if ((system_flags & Flag.DRAFT.mask) != 0) result[--size] = Flag.DRAFT; |
| if ((system_flags & Flag.DELETED.mask) != 0) result[--size] = Flag.DELETED; |
| if ((system_flags & Flag.ANSWERED.mask) != 0) result[--size] = Flag.ANSWERED; |
| return result; |
| } |
| |
| /** |
| * Return a list of user flags that have been set |
| * @return a list of user flags |
| */ |
| public String[] getUserFlags() { |
| return (String[]) user_flags.values().toArray(new String[user_flags.values().size()]); |
| } |
| |
| /** |
| * Unset the supplied system flag. |
| * Question: what happens if we unset the USER flags and user flags are set? |
| * @param flag the flag to clear |
| */ |
| public void remove(Flag flag) { |
| system_flags &= ~flag.mask; |
| } |
| |
| /** |
| * Unset all flags from the supplied instance. |
| * @param flags the flags to clear |
| */ |
| public void remove(Flags flags) { |
| system_flags &= ~flags.system_flags; |
| user_flags.keySet().removeAll(flags.user_flags.keySet()); |
| } |
| |
| /** |
| * Unset the supplied user flag. |
| * @param name the flag to clear |
| */ |
| public void remove(String name) { |
| user_flags.remove(name.toLowerCase()); |
| } |
| } |