1. /*
  2. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  3. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. */
  5. package javax.mail;
  6. import java.io.Serializable;
  7. import java.util.*;
  8. /**
  9. * The Flags class represents the set of flags on a Message. Flags
  10. * are composed of predefined system flags, and user defined flags. <p>
  11. *
  12. * A System flag is represented by the <code>Flags.Flag</code>
  13. * inner class. A User defined flag is represented as a String.
  14. * User flags are case-independent. <p>
  15. *
  16. * A set of standard system flags are predefined. Most folder
  17. * implementations are expected to support these flags. Some
  18. * implementations may also support arbitrary user-defined flags. The
  19. * <code>getPermanentFlags</code> method on a Folder returns a Flags
  20. * object that holds all the flags that are supported by that folder
  21. * implementation. <p>
  22. *
  23. * A Flags object is serializable so that (for example) the
  24. * use of Flags objects in search terms can be serialized
  25. * along with the search terms. <p>
  26. *
  27. * <strong>Warning:</strong>
  28. * Serialized objects of this class may not be compatible with future
  29. * JavaMail API releases. The current serialization support is
  30. * appropriate for short term storage. <p>
  31. *
  32. * The below code sample illustrates how to set, examine and get the
  33. * flags for a message. <p>
  34. * <pre>
  35. *
  36. * Message m = folder.getMessage(1);
  37. * m.setFlag(Flags.Flag.DELETED, true); // set the DELETED flag
  38. *
  39. * // Check if DELETED flag is set of this message
  40. * if (m.isSet(Flags.Flag.DELETED))
  41. * System.out.println("DELETED message");
  42. *
  43. * // Examine ALL system flags for this message
  44. * Flags flags = m.getFlags();
  45. * Flags.Flag[] sf = flags.getSystemFlags();
  46. * for (int i = 0; i < sf.length; i++) {
  47. * if (sf[i] == Flags.Flag.DELETED)
  48. * System.out.println("DELETED message");
  49. * else if (sf[i] == Flags.Flag.SEEN)
  50. * System.out.println("SEEN message");
  51. * ......
  52. * ......
  53. * }
  54. * </pre>
  55. * <p>
  56. *
  57. * @see Folder#getPermanentFlags
  58. * @author John Mani
  59. * @author Bill Shannon
  60. */
  61. public class Flags implements Cloneable, Serializable {
  62. private int system_flags = 0;
  63. private Hashtable user_flags = null;
  64. private final static int ANSWERED_BIT = 0x01;
  65. private final static int DELETED_BIT = 0x02;
  66. private final static int DRAFT_BIT = 0x04;
  67. private final static int FLAGGED_BIT = 0x08;
  68. private final static int RECENT_BIT = 0x10;
  69. private final static int SEEN_BIT = 0x20;
  70. private final static int USER_BIT = 0x80000000;
  71. /**
  72. * This inner class represents an individual system flag. A set
  73. * of standard system flag objects are predefined here.
  74. */
  75. public static final class Flag {
  76. /**
  77. * This message has been answered. This flag is set by clients
  78. * to indicate that this message has been answered to.
  79. */
  80. public static final Flag ANSWERED = new Flag(ANSWERED_BIT);
  81. /**
  82. * This message is marked deleted. Clients set this flag to
  83. * mark a message as deleted. The expunge operation on a folder
  84. * removes all messages in that folder that are marked for deletion.
  85. */
  86. public static final Flag DELETED = new Flag(DELETED_BIT);
  87. /**
  88. * This message is a draft. This flag is set by clients
  89. * to indicate that the message is a draft message.
  90. */
  91. public static final Flag DRAFT = new Flag(DRAFT_BIT);
  92. /**
  93. * This message is flagged. No semantic is defined for this flag.
  94. * Clients alter this flag.
  95. */
  96. public static final Flag FLAGGED = new Flag(FLAGGED_BIT);
  97. /**
  98. * This message is recent. Folder implementations set this flag
  99. * to indicate that this message is new to this folder, that is,
  100. * it has arrived since the last time this folder was opened. <p>
  101. *
  102. * Clients cannot alter this flag.
  103. */
  104. public static final Flag RECENT = new Flag(RECENT_BIT);
  105. /**
  106. * This message is seen. This flag is implicitly set by the
  107. * implementation when the this Message's content is returned
  108. * to the client in some form. The <code>getInputStream</code>
  109. * and <code>getContent</code> methods on Message cause this
  110. * flag to be set. <p>
  111. *
  112. * Clients can alter this flag.
  113. */
  114. public static final Flag SEEN = new Flag(SEEN_BIT);
  115. /**
  116. * A special flag that indicates that this folder supports
  117. * user defined flags. <p>
  118. *
  119. * The implementation sets this flag. Clients cannot alter
  120. * this flag but can use it to determine if a folder supports
  121. * user defined flags by using
  122. * <code>folder.getPermanentFlags().contains(Flags.Flag.USER)</code>.
  123. */
  124. public static final Flag USER = new Flag(USER_BIT);
  125. // flags are stored as bits for efficiency
  126. private int bit;
  127. private Flag(int bit) {
  128. this.bit = bit;
  129. }
  130. }
  131. /**
  132. * Construct an empty Flags object.
  133. */
  134. public Flags() { }
  135. /**
  136. * Construct a Flags object initialized with the given flags.
  137. *
  138. * @param flags the flags for initialization
  139. */
  140. public Flags(Flags flags) {
  141. this.system_flags = flags.system_flags;
  142. if (flags.user_flags != null)
  143. this.user_flags = (Hashtable)flags.user_flags.clone();
  144. }
  145. /**
  146. * Construct a Flags object initialized with the given system flag.
  147. *
  148. * @param flag the flag for initialization
  149. */
  150. public Flags(Flag flag) {
  151. this.system_flags |= flag.bit;
  152. }
  153. /**
  154. * Construct a Flags object initialized with the given user flag.
  155. *
  156. * @param flag the flag for initialization
  157. */
  158. public Flags(String flag) {
  159. user_flags = new Hashtable(1);
  160. user_flags.put(flag, flag);
  161. }
  162. /**
  163. * Add the specified system flag to this Flags object.
  164. *
  165. * @param flag the flag to add
  166. */
  167. public void add(Flag flag) {
  168. system_flags |= flag.bit;
  169. }
  170. /**
  171. * Add the specified user flag to this Flags object.
  172. *
  173. * @param flag the flag to add
  174. */
  175. public void add(String flag) {
  176. if (user_flags == null)
  177. user_flags = new Hashtable(1);
  178. user_flags.put(flag.toLowerCase(), flag);
  179. }
  180. /**
  181. * Add all the flags in the given Flags object to this
  182. * Flags object.
  183. *
  184. * @param flags Flags object
  185. */
  186. public void add(Flags f) {
  187. system_flags |= f.system_flags; // add system flags
  188. if (f.user_flags != null) { // add user-defined flags
  189. if (user_flags == null)
  190. user_flags = new Hashtable(1);
  191. Enumeration e = f.user_flags.keys();
  192. while (e.hasMoreElements()) {
  193. String s = (String)e.nextElement();
  194. user_flags.put(s, f.user_flags.get(s));
  195. }
  196. }
  197. }
  198. /**
  199. * Remove the specified system flag from this Flags object.
  200. *
  201. * @param flag the flag to be removed
  202. */
  203. public void remove(Flag flag) {
  204. system_flags &= ~flag.bit;
  205. }
  206. /**
  207. * Remove the specified user flag from this Flags object.
  208. *
  209. * @param flag the flag to be removed
  210. */
  211. public void remove(String flag) {
  212. if (user_flags != null)
  213. user_flags.remove(flag.toLowerCase());
  214. }
  215. /**
  216. * Remove all flags in the given Flags object from this
  217. * Flags object.
  218. *
  219. * @param flag the flag to be removed
  220. */
  221. public void remove(Flags f) {
  222. system_flags &= ~f.system_flags; // remove system flags
  223. if (f.user_flags != null) {
  224. if (user_flags == null)
  225. return;
  226. Enumeration e = f.user_flags.keys();
  227. while (e.hasMoreElements())
  228. user_flags.remove(e.nextElement());
  229. }
  230. }
  231. /**
  232. * Check whether the specified system flag is present in this Flags object.
  233. *
  234. * @return true of the given flag is present, otherwise false.
  235. */
  236. public boolean contains(Flag flag) {
  237. return (system_flags & flag.bit) != 0;
  238. }
  239. /**
  240. * Check whether the specified user flag is present in this Flags object.
  241. *
  242. * @return true of the given flag is present, otherwise false.
  243. */
  244. public boolean contains(String flag) {
  245. if (user_flags == null)
  246. return false;
  247. else
  248. return user_flags.containsKey(flag.toLowerCase());
  249. }
  250. /**
  251. * Check whether all the flags in the specified Flags object are
  252. * present in this Flags object.
  253. *
  254. * @return true if all flags in the given Flags object are present,
  255. * otherwise false.
  256. */
  257. public boolean contains(Flags f) {
  258. // Check system flags
  259. if ((f.system_flags & system_flags) != f.system_flags)
  260. return false;
  261. // Check user flags
  262. if (f.user_flags != null) {
  263. if (user_flags == null)
  264. return false;
  265. Enumeration e = f.user_flags.keys();
  266. while (e.hasMoreElements()) {
  267. if (!user_flags.containsKey(e.nextElement()))
  268. return false;
  269. }
  270. }
  271. // If we've made it till here, return true
  272. return true;
  273. }
  274. /**
  275. * Check whether the two Flags objects are equal.
  276. *
  277. * @return true if they're equal
  278. */
  279. public boolean equals(Object obj) {
  280. if (!(obj instanceof Flags))
  281. return false;
  282. Flags f = (Flags)obj;
  283. // Check system flags
  284. if (f.system_flags != this.system_flags)
  285. return false;
  286. // Check user flags
  287. if (f.user_flags == null && this.user_flags == null)
  288. return true;
  289. if (f.user_flags != null && this.user_flags != null &&
  290. f.user_flags.size() == this.user_flags.size()) {
  291. Enumeration e = f.user_flags.keys();
  292. while (e.hasMoreElements()) {
  293. if (!this.user_flags.containsKey(e.nextElement()))
  294. return false;
  295. }
  296. return true;
  297. }
  298. return false;
  299. }
  300. /**
  301. * Compute a hash code for this Flags object.
  302. *
  303. * @return the hash code
  304. */
  305. public int hashCode() {
  306. int hash = system_flags;
  307. if (user_flags != null) {
  308. Enumeration e = user_flags.keys();
  309. while (e.hasMoreElements())
  310. hash += ((String)e.nextElement()).hashCode();
  311. }
  312. return hash;
  313. }
  314. /**
  315. * Return all the system flags in this Flags object. Returns
  316. * an array of size zero if no flags are set.
  317. *
  318. * @return array of Flags.Flag objects representing system flags
  319. */
  320. public Flag[] getSystemFlags() {
  321. Vector v = new Vector();
  322. if ((system_flags & ANSWERED_BIT) != 0)
  323. v.addElement(Flag.ANSWERED);
  324. if ((system_flags & DELETED_BIT) != 0)
  325. v.addElement(Flag.DELETED);
  326. if ((system_flags & DRAFT_BIT) != 0)
  327. v.addElement(Flag.DRAFT);
  328. if ((system_flags & FLAGGED_BIT) != 0)
  329. v.addElement(Flag.FLAGGED);
  330. if ((system_flags & RECENT_BIT) != 0)
  331. v.addElement(Flag.RECENT);
  332. if ((system_flags & SEEN_BIT) != 0)
  333. v.addElement(Flag.SEEN);
  334. if ((system_flags & USER_BIT) != 0)
  335. v.addElement(Flag.USER);
  336. Flag[] f = new Flag[v.size()];
  337. v.copyInto(f);
  338. return f;
  339. }
  340. /**
  341. * Return all the user flags in this Flags object. Returns
  342. * an array of size zero if no flags are set.
  343. *
  344. * @return array of Strings, each String represents a flag.
  345. */
  346. public String[] getUserFlags() {
  347. Vector v = new Vector();
  348. if (user_flags != null) {
  349. Enumeration e = user_flags.elements();
  350. while (e.hasMoreElements())
  351. v.addElement(e.nextElement());
  352. }
  353. String[] f = new String[v.size()];
  354. v.copyInto(f);
  355. return f;
  356. }
  357. /**
  358. * Returns a clone of this Flags object.
  359. */
  360. public Object clone() {
  361. return new Flags(this);
  362. }
  363. /*****
  364. public static void main(String argv[]) throws Exception {
  365. // a new flags object
  366. Flags f1 = new Flags();
  367. f1.add(Flags.Flag.DELETED);
  368. f1.add(Flags.Flag.SEEN);
  369. f1.add(Flags.Flag.RECENT);
  370. f1.add(Flags.Flag.ANSWERED);
  371. // check copy constructor with only system flags
  372. Flags fc = new Flags(f1);
  373. if (f1.equals(fc) && fc.equals(f1))
  374. System.out.println("success");
  375. else
  376. System.out.println("fail");
  377. // check clone with only system flags
  378. fc = (Flags)f1.clone();
  379. if (f1.equals(fc) && fc.equals(f1))
  380. System.out.println("success");
  381. else
  382. System.out.println("fail");
  383. // add a user flag and make sure it still works right
  384. f1.add("MyFlag");
  385. // shouldn't be equal here
  386. if (!f1.equals(fc) && !fc.equals(f1))
  387. System.out.println("success");
  388. else
  389. System.out.println("fail");
  390. // check clone
  391. fc = (Flags)f1.clone();
  392. if (f1.equals(fc) && fc.equals(f1))
  393. System.out.println("success");
  394. else
  395. System.out.println("fail");
  396. // make sure user flag hash tables are separate
  397. fc.add("AnotherFlag");
  398. if (!f1.equals(fc) && !fc.equals(f1))
  399. System.out.println("success");
  400. else
  401. System.out.println("fail");
  402. // check copy constructor
  403. fc = new Flags(f1);
  404. if (f1.equals(fc) && fc.equals(f1))
  405. System.out.println("success");
  406. else
  407. System.out.println("fail");
  408. // another new flags object
  409. Flags f2 = new Flags(Flags.Flag.ANSWERED);
  410. f2.add("MyFlag");
  411. if (f1.contains(Flags.Flag.DELETED))
  412. System.out.println("success");
  413. else
  414. System.out.println("fail");
  415. if (f1.contains(Flags.Flag.SEEN))
  416. System.out.println("success");
  417. else
  418. System.out.println("fail");
  419. if (f1.contains(Flags.Flag.RECENT))
  420. System.out.println("success");
  421. else
  422. System.out.println("fail");
  423. if (f1.contains("MyFlag"))
  424. System.out.println("success");
  425. else
  426. System.out.println("fail");
  427. if (f2.contains(Flags.Flag.ANSWERED))
  428. System.out.println("success");
  429. else
  430. System.out.println("fail");
  431. System.out.println("----------------");
  432. String[] s = f1.getUserFlags();
  433. for (int i = 0; i < s.length; i++)
  434. System.out.println(s[i]);
  435. System.out.println("----------------");
  436. s = f2.getUserFlags();
  437. for (int i = 0; i < s.length; i++)
  438. System.out.println(s[i]);
  439. System.out.println("----------------");
  440. if (f1.contains(f2)) // this should be true
  441. System.out.println("success");
  442. else
  443. System.out.println("fail");
  444. if (!f2.contains(f1)) // this should be false
  445. System.out.println("success");
  446. else
  447. System.out.println("fail");
  448. Flags f3 = new Flags();
  449. f3.add(Flags.Flag.DELETED);
  450. f3.add(Flags.Flag.SEEN);
  451. f3.add(Flags.Flag.RECENT);
  452. f3.add(Flags.Flag.ANSWERED);
  453. f3.add("ANOTHERFLAG");
  454. f3.add("MYFLAG");
  455. f1.add("AnotherFlag");
  456. if (f1.equals(f3))
  457. System.out.println("equals success");
  458. else
  459. System.out.println("fail");
  460. if (f3.equals(f1))
  461. System.out.println("equals success");
  462. else
  463. System.out.println("fail");
  464. System.out.println("f1 hash code " + f1.hashCode());
  465. System.out.println("f3 hash code " + f3.hashCode());
  466. if (f1.hashCode() == f3.hashCode())
  467. System.out.println("success");
  468. else
  469. System.out.println("fail");
  470. }
  471. ****/
  472. }