001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020 package javax.mail; 021 022 import java.io.Serializable; 023 import java.util.Hashtable; 024 import java.util.Iterator; 025 import java.util.LinkedList; 026 import java.util.List; 027 028 /** 029 * Representation of flags that may be associated with a message. 030 * Flags can either be system flags, defined by the {@link Flags.Flag Flag} inner class, 031 * or user-defined flags defined by a String. The system flags represent those expected 032 * to be provided by most folder systems; user-defined flags allow for additional flags 033 * on a per-provider basis. 034 * <p/> 035 * This class is Serializable but compatibility is not guaranteed across releases. 036 * 037 * @version $Rev: 920714 $ $Date: 2010-03-09 01:55:49 -0500 (Tue, 09 Mar 2010) $ 038 */ 039 public class Flags implements Cloneable, Serializable { 040 041 private static final long serialVersionUID = 6243590407214169028L; 042 043 public static final class Flag { 044 /** 045 * Flag that indicates that the message has been replied to; has a bit value of 1. 046 */ 047 public static final Flag ANSWERED = new Flag(1); 048 /** 049 * Flag that indicates that the message has been marked for deletion and 050 * should be removed on a subsequent expunge operation; has a bit value of 2. 051 */ 052 public static final Flag DELETED = new Flag(2); 053 /** 054 * Flag that indicates that the message is a draft; has a bit value of 4. 055 */ 056 public static final Flag DRAFT = new Flag(4); 057 /** 058 * Flag that indicates that the message has been flagged; has a bit value of 8. 059 */ 060 public static final Flag FLAGGED = new Flag(8); 061 /** 062 * Flag that indicates that the message has been delivered since the last time 063 * this folder was opened; has a bit value of 16. 064 */ 065 public static final Flag RECENT = new Flag(16); 066 /** 067 * Flag that indicates that the message has been viewed; has a bit value of 32. 068 * This flag is set by the {@link Message#getInputStream()} and {@link Message#getContent()} 069 * methods. 070 */ 071 public static final Flag SEEN = new Flag(32); 072 /** 073 * Flags that indicates if this folder supports user-defined flags; has a bit value of 0x80000000. 074 */ 075 public static final Flag USER = new Flag(0x80000000); 076 077 private final int mask; 078 079 private Flag(int mask) { 080 this.mask = mask; 081 } 082 } 083 084 // the Serialized form of this class required the following two fields to be persisted 085 // this leads to a specific type of implementation 086 private int system_flags; 087 private final Hashtable user_flags; 088 089 /** 090 * Construct a Flags instance with no flags set. 091 */ 092 public Flags() { 093 user_flags = new Hashtable(); 094 } 095 096 /** 097 * Construct a Flags instance with a supplied system flag set. 098 * @param flag the system flag to set 099 */ 100 public Flags(Flag flag) { 101 system_flags = flag.mask; 102 user_flags = new Hashtable(); 103 } 104 105 /** 106 * Construct a Flags instance with a same flags set. 107 * @param flags the instance to copy 108 */ 109 public Flags(Flags flags) { 110 system_flags = flags.system_flags; 111 user_flags = new Hashtable(flags.user_flags); 112 } 113 114 /** 115 * Construct a Flags instance with the supplied user flags set. 116 * Question: should this automatically set the USER system flag? 117 * @param name the user flag to set 118 */ 119 public Flags(String name) { 120 user_flags = new Hashtable(); 121 user_flags.put(name.toLowerCase(), name); 122 } 123 124 /** 125 * Set a system flag. 126 * @param flag the system flag to set 127 */ 128 public void add(Flag flag) { 129 system_flags |= flag.mask; 130 } 131 132 /** 133 * Set all system and user flags from the supplied Flags. 134 * Question: do we need to check compatibility of USER flags? 135 * @param flags the Flags to add 136 */ 137 public void add(Flags flags) { 138 system_flags |= flags.system_flags; 139 user_flags.putAll(flags.user_flags); 140 } 141 142 /** 143 * Set a user flag. 144 * Question: should this fail if the USER system flag is not set? 145 * @param name the user flag to set 146 */ 147 public void add(String name) { 148 user_flags.put(name.toLowerCase(), name); 149 } 150 151 /** 152 * Return a copy of this instance. 153 * @return a copy of this instance 154 */ 155 public Object clone() { 156 return new Flags(this); 157 } 158 159 /** 160 * See if the supplied system flags are set 161 * @param flag the system flags to check for 162 * @return true if the flags are set 163 */ 164 public boolean contains(Flag flag) { 165 return (system_flags & flag.mask) != 0; 166 } 167 168 /** 169 * See if all of the supplied Flags are set 170 * @param flags the flags to check for 171 * @return true if all the supplied system and user flags are set 172 */ 173 public boolean contains(Flags flags) { 174 return ((system_flags & flags.system_flags) == flags.system_flags) 175 && user_flags.keySet().containsAll(flags.user_flags.keySet()); 176 } 177 178 /** 179 * See if the supplied user flag is set 180 * @param name the user flag to check for 181 * @return true if the flag is set 182 */ 183 public boolean contains(String name) { 184 return user_flags.containsKey(name.toLowerCase()); 185 } 186 187 /** 188 * Equality is defined as true if the other object is a instanceof Flags with the 189 * same system and user flags set (using a case-insensitive name comparison for user flags). 190 * @param other the instance to compare against 191 * @return true if the two instance are the same 192 */ 193 public boolean equals(Object other) { 194 if (other == this) return true; 195 if (other instanceof Flags == false) return false; 196 final Flags flags = (Flags) other; 197 return system_flags == flags.system_flags && user_flags.keySet().equals(flags.user_flags.keySet()); 198 } 199 200 /** 201 * Calculate a hashCode for this instance 202 * @return a hashCode for this instance 203 */ 204 public int hashCode() { 205 return system_flags ^ user_flags.keySet().hashCode(); 206 } 207 208 /** 209 * Return a list of {@link Flags.Flag Flags} containing the system flags that have been set 210 * @return the system flags that have been set 211 */ 212 public Flag[] getSystemFlags() { 213 // assumption: it is quicker to calculate the size than it is to reallocate the array 214 int size = 0; 215 if ((system_flags & Flag.ANSWERED.mask) != 0) size += 1; 216 if ((system_flags & Flag.DELETED.mask) != 0) size += 1; 217 if ((system_flags & Flag.DRAFT.mask) != 0) size += 1; 218 if ((system_flags & Flag.FLAGGED.mask) != 0) size += 1; 219 if ((system_flags & Flag.RECENT.mask) != 0) size += 1; 220 if ((system_flags & Flag.SEEN.mask) != 0) size += 1; 221 if ((system_flags & Flag.USER.mask) != 0) size += 1; 222 Flag[] result = new Flag[size]; 223 if ((system_flags & Flag.USER.mask) != 0) result[--size] = Flag.USER; 224 if ((system_flags & Flag.SEEN.mask) != 0) result[--size] = Flag.SEEN; 225 if ((system_flags & Flag.RECENT.mask) != 0) result[--size] = Flag.RECENT; 226 if ((system_flags & Flag.FLAGGED.mask) != 0) result[--size] = Flag.FLAGGED; 227 if ((system_flags & Flag.DRAFT.mask) != 0) result[--size] = Flag.DRAFT; 228 if ((system_flags & Flag.DELETED.mask) != 0) result[--size] = Flag.DELETED; 229 if ((system_flags & Flag.ANSWERED.mask) != 0) result[--size] = Flag.ANSWERED; 230 return result; 231 } 232 233 /** 234 * Return a list of user flags that have been set 235 * @return a list of user flags 236 */ 237 public String[] getUserFlags() { 238 return (String[]) user_flags.values().toArray(new String[user_flags.values().size()]); 239 } 240 241 /** 242 * Unset the supplied system flag. 243 * Question: what happens if we unset the USER flags and user flags are set? 244 * @param flag the flag to clear 245 */ 246 public void remove(Flag flag) { 247 system_flags &= ~flag.mask; 248 } 249 250 /** 251 * Unset all flags from the supplied instance. 252 * @param flags the flags to clear 253 */ 254 public void remove(Flags flags) { 255 system_flags &= ~flags.system_flags; 256 user_flags.keySet().removeAll(flags.user_flags.keySet()); 257 } 258 259 /** 260 * Unset the supplied user flag. 261 * @param name the flag to clear 262 */ 263 public void remove(String name) { 264 user_flags.remove(name.toLowerCase()); 265 } 266 }