Skip to content

Package: Flags$Flag

Flags$Flag

nameinstructionbranchcomplexitylinemethod
Flags.Flag(int)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 36
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%

Coverage

1: /*
2: * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package jakarta.mail;
18:
19: import java.io.Serializable;
20: import java.util.*;
21:
22: /**
23: * The Flags class represents the set of flags on a Message. Flags
24: * are composed of predefined system flags, and user defined flags. <p>
25: *
26: * A System flag is represented by the <code>Flags.Flag</code>
27: * inner class. A User defined flag is represented as a String.
28: * User flags are case-independent. <p>
29: *
30: * A set of standard system flags are predefined. Most folder
31: * implementations are expected to support these flags. Some
32: * implementations may also support arbitrary user-defined flags. The
33: * <code>getPermanentFlags</code> method on a Folder returns a Flags
34: * object that holds all the flags that are supported by that folder
35: * implementation. <p>
36: *
37: * A Flags object is serializable so that (for example) the
38: * use of Flags objects in search terms can be serialized
39: * along with the search terms. <p>
40: *
41: * <strong>Warning:</strong>
42: * Serialized objects of this class may not be compatible with future
43: * Jakarta Mail API releases. The current serialization support is
44: * appropriate for short term storage. <p>
45: *
46: * The below code sample illustrates how to set, examine, and get the
47: * flags for a message.
48: * <pre>
49: *
50: * Message m = folder.getMessage(1);
51: * m.setFlag(Flags.Flag.DELETED, true); // set the DELETED flag
52: *
53: * // Check if DELETED flag is set on this message
54: * if (m.isSet(Flags.Flag.DELETED))
55: *        System.out.println("DELETED message");
56: *
57: * // Examine ALL system flags for this message
58: * Flags flags = m.getFlags();
59: * Flags.Flag[] sf = flags.getSystemFlags();
60: * for (int i = 0; i < sf.length; i++) {
61: *        if (sf[i] == Flags.Flag.DELETED)
62: * System.out.println("DELETED message");
63: *        else if (sf[i] == Flags.Flag.SEEN)
64: * System.out.println("SEEN message");
65: * ......
66: * ......
67: * }
68: * </pre>
69: * <p>
70: *
71: * @see Folder#getPermanentFlags
72: * @author John Mani
73: * @author Bill Shannon
74: */
75:
76: public class Flags implements Cloneable, Serializable {
77:
78: private int system_flags = 0;
79: // used as a case-independent Set that preserves the original case,
80: // the key is the lowercase flag name and the value is the original
81: private Hashtable<String, String> user_flags = null;
82:
83: private final static int ANSWERED_BIT         = 0x01;
84: private final static int DELETED_BIT         = 0x02;
85: private final static int DRAFT_BIT                 = 0x04;
86: private final static int FLAGGED_BIT         = 0x08;
87: private final static int RECENT_BIT                = 0x10;
88: private final static int SEEN_BIT                = 0x20;
89: private final static int USER_BIT                = 0x80000000;
90:
91: private static final long serialVersionUID = 6243590407214169028L;
92:
93: /**
94: * This inner class represents an individual system flag. A set
95: * of standard system flag objects are predefined here.
96: */
97: public static final class Flag {
98:         /**
99:          * This message has been answered. This flag is set by clients
100:          * to indicate that this message has been answered to.
101:          */
102:         public static final Flag ANSWERED = new Flag(ANSWERED_BIT);
103:
104:         /**
105:          * This message is marked deleted. Clients set this flag to
106:          * mark a message as deleted. The expunge operation on a folder
107:          * removes all messages in that folder that are marked for deletion.
108:          */
109:         public static final Flag DELETED = new Flag(DELETED_BIT);
110:
111:         /**
112:          * This message is a draft. This flag is set by clients
113:          * to indicate that the message is a draft message.
114:          */
115:         public static final Flag DRAFT = new Flag(DRAFT_BIT);
116:
117:         /**
118:          * This message is flagged. No semantic is defined for this flag.
119:          * Clients alter this flag.
120:          */
121:         public static final Flag FLAGGED = new Flag(FLAGGED_BIT);
122:
123:         /**
124:          * This message is recent. Folder implementations set this flag
125:          * to indicate that this message is new to this folder, that is,
126:          * it has arrived since the last time this folder was opened. <p>
127:          *
128:          * Clients cannot alter this flag.
129:          */
130:         public static final Flag RECENT = new Flag(RECENT_BIT);
131:
132:         /**
133:          * This message is seen. This flag is implicitly set by the
134:          * implementation when this Message's content is returned
135:          * to the client in some form. The <code>getInputStream</code>
136:          * and <code>getContent</code> methods on Message cause this
137:          * flag to be set. <p>
138:          *
139:          * Clients can alter this flag.
140:          */
141:         public static final Flag SEEN = new Flag(SEEN_BIT);
142:
143:         /**
144:          * A special flag that indicates that this folder supports
145:          * user defined flags. <p>
146:          *
147:          * The implementation sets this flag. Clients cannot alter
148:          * this flag but can use it to determine if a folder supports
149:          * user defined flags by using
150:          * <code>folder.getPermanentFlags().contains(Flags.Flag.USER)</code>.
151:          */
152:         public static final Flag USER = new Flag(USER_BIT);
153:
154:         // flags are stored as bits for efficiency
155:         private int bit;
156:         private Flag(int bit) {
157:          this.bit = bit;
158:         }
159: }
160:
161:
162: /**
163: * Construct an empty Flags object.
164: */
165: public Flags() { }
166:
167: /**
168: * Construct a Flags object initialized with the given flags.
169: *
170: * @param flags        the flags for initialization
171: */
172: @SuppressWarnings("unchecked")
173: public Flags(Flags flags) {
174:         this.system_flags = flags.system_flags;
175:         if (flags.user_flags != null)
176:          this.user_flags = (Hashtable)flags.user_flags.clone();
177: }
178:
179: /**
180: * Construct a Flags object initialized with the given system flag.
181: *
182: * @param flag        the flag for initialization
183: */
184: public Flags(Flag flag) {
185:         this.system_flags |= flag.bit;
186: }
187:
188: /**
189: * Construct a Flags object initialized with the given user flag.
190: *
191: * @param flag        the flag for initialization
192: */
193: public Flags(String flag) {
194:         user_flags = new Hashtable<>(1);
195:         user_flags.put(flag.toLowerCase(Locale.ENGLISH), flag);
196: }
197:
198: /**
199: * Add the specified system flag to this Flags object.
200: *
201: * @param flag        the flag to add
202: */
203: public void add(Flag flag) {
204:         system_flags |= flag.bit;
205: }
206:
207: /**
208: * Add the specified user flag to this Flags object.
209: *
210: * @param flag        the flag to add
211: */
212: public void add(String flag) {
213:         if (user_flags == null)
214:          user_flags = new Hashtable<>(1);
215:         user_flags.put(flag.toLowerCase(Locale.ENGLISH), flag);
216: }
217:
218: /**
219: * Add all the flags in the given Flags object to this
220: * Flags object.
221: *
222: * @param f        Flags object
223: */
224: public void add(Flags f) {
225:         system_flags |= f.system_flags; // add system flags
226:
227:         if (f.user_flags != null) { // add user-defined flags
228:          if (user_flags == null)
229:                 user_flags = new Hashtable<>(1);
230:
231:          Enumeration<String> e = f.user_flags.keys();
232:
233:          while (e.hasMoreElements()) {
234:                 String s = e.nextElement();
235:                 user_flags.put(s, f.user_flags.get(s));
236:          }
237:         }
238: }
239:
240: /**
241: * Remove the specified system flag from this Flags object.
242: *
243: * @param        flag         the flag to be removed
244: */
245: public void remove(Flag flag) {
246:         system_flags &= ~flag.bit;
247: }
248:
249: /**
250: * Remove the specified user flag from this Flags object.
251: *
252: * @param        flag         the flag to be removed
253: */
254: public void remove(String flag) {
255:         if (user_flags != null)
256:          user_flags.remove(flag.toLowerCase(Locale.ENGLISH));
257: }
258:
259: /**
260: * Remove all flags in the given Flags object from this
261: * Flags object.
262: *
263: * @param        f         the flag to be removed
264: */
265: public void remove(Flags f) {
266:         system_flags &= ~f.system_flags; // remove system flags
267:
268:         if (f.user_flags != null) {
269:          if (user_flags == null)
270:                 return;
271:
272:          Enumeration<String> e = f.user_flags.keys();
273:          while (e.hasMoreElements())
274:                 user_flags.remove(e.nextElement());
275:         }
276: }
277:
278: /**
279: * Remove any flags <strong>not</strong> in the given Flags object.
280: * Useful for clearing flags not supported by a server. If the
281: * given Flags object includes the Flags.Flag.USER flag, all user
282: * flags in this Flags object are retained.
283: *
284: * @param        f        the flags to keep
285: * @return                true if this Flags object changed
286: * @since                JavaMail 1.6
287: */
288: public boolean retainAll(Flags f) {
289:         boolean changed = false;
290:         int sf = system_flags & f.system_flags;
291:         if (system_flags != sf) {
292:          system_flags = sf;
293:          changed = true;
294:         }
295:
296:         // if we have user flags, and the USER flag is not set in "f",
297:         // determine which user flags to clear
298:         if (user_flags != null && (f.system_flags & USER_BIT) == 0) {
299:          if (f.user_flags != null) {
300:                 Enumeration<String> e = user_flags.keys();
301:                 while (e.hasMoreElements()) {
302:                  String key = e.nextElement();
303:                  if (!f.user_flags.containsKey(key)) {
304:                         user_flags.remove(key);
305:                         changed = true;
306:                  }
307:                 }
308:          } else {
309:                 // if anything in user_flags, throw them away
310:                 changed = user_flags.size() > 0;
311:                 user_flags = null;
312:          }
313:         }
314:         return changed;
315: }
316:
317: /**
318: * Check whether the specified system flag is present in this Flags object.
319: *
320: * @param        flag        the flag to test
321: * @return                 true of the given flag is present, otherwise false.
322: */
323: public boolean contains(Flag flag) {
324:         return (system_flags & flag.bit) != 0;
325: }
326:
327: /**
328: * Check whether the specified user flag is present in this Flags object.
329: *
330: * @param        flag        the flag to test
331: * @return                 true of the given flag is present, otherwise false.
332: */
333: public boolean contains(String flag) {
334:         if (user_flags == null)
335:          return false;
336:         else
337:          return user_flags.containsKey(flag.toLowerCase(Locale.ENGLISH));
338: }
339:
340: /**
341: * Check whether all the flags in the specified Flags object are
342: * present in this Flags object.
343: *
344: * @param        f        the flags to test
345: * @return        true if all flags in the given Flags object are present,
346: *                otherwise false.
347: */
348: public boolean contains(Flags f) {
349:         // Check system flags
350:         if ((f.system_flags & system_flags) != f.system_flags)
351:          return false;
352:
353:         // Check user flags
354:         if (f.user_flags != null) {
355:          if (user_flags == null)
356:                 return false;
357:          Enumeration<String> e = f.user_flags.keys();
358:
359:          while (e.hasMoreElements()) {
360:                 if (!user_flags.containsKey(e.nextElement()))
361:                  return false;
362:          }
363:         }
364:
365:         // If we've made it till here, return true
366:         return true;
367: }
368:
369: /**
370: * Check whether the two Flags objects are equal.
371: *
372: * @return        true if they're equal
373: */
374: @Override
375: public boolean equals(Object obj) {
376:         if (!(obj instanceof Flags))
377:          return false;
378:
379:         Flags f = (Flags)obj;
380:
381:         // Check system flags
382:         if (f.system_flags != this.system_flags)
383:          return false;
384:
385:         // Check user flags
386:         int size = this.user_flags == null ? 0 : this.user_flags.size();
387:         int fsize = f.user_flags == null ? 0 : f.user_flags.size();
388:         if (size == 0 && fsize == 0)
389:          return true;
390:         if (f.user_flags != null && this.user_flags != null && fsize == size)
391:          return user_flags.keySet().equals(f.user_flags.keySet());
392:
393:         return false;
394: }
395:
396: /**
397: * Compute a hash code for this Flags object.
398: *
399: * @return        the hash code
400: */
401: @Override
402: public int hashCode() {
403:         int hash = system_flags;
404:         if (user_flags != null) {
405:          Enumeration<String> e = user_flags.keys();
406:          while (e.hasMoreElements())
407:                 hash += e.nextElement().hashCode();
408:         }
409:         return hash;
410: }
411:
412: /**
413: * Return all the system flags in this Flags object. Returns
414: * an array of size zero if no flags are set.
415: *
416: * @return        array of Flags.Flag objects representing system flags
417: */
418: public Flag[] getSystemFlags() {
419:         Vector<Flag> v = new Vector<>();
420:         if ((system_flags & ANSWERED_BIT) != 0)
421:          v.addElement(Flag.ANSWERED);
422:         if ((system_flags & DELETED_BIT) != 0)
423:          v.addElement(Flag.DELETED);
424:         if ((system_flags & DRAFT_BIT) != 0)
425:          v.addElement(Flag.DRAFT);
426:         if ((system_flags & FLAGGED_BIT) != 0)
427:          v.addElement(Flag.FLAGGED);
428:         if ((system_flags & RECENT_BIT) != 0)
429:          v.addElement(Flag.RECENT);
430:         if ((system_flags & SEEN_BIT) != 0)
431:          v.addElement(Flag.SEEN);
432:         if ((system_flags & USER_BIT) != 0)
433:          v.addElement(Flag.USER);
434:
435:         Flag[] f = new Flag[v.size()];
436:         v.copyInto(f);
437:         return f;
438: }
439:
440: /**
441: * Return all the user flags in this Flags object. Returns
442: * an array of size zero if no flags are set.
443: *
444: * @return        array of Strings, each String represents a flag.
445: */
446: public String[] getUserFlags() {
447:         Vector<String> v = new Vector<>();
448:         if (user_flags != null) {
449:          Enumeration<String> e = user_flags.elements();
450:
451:          while (e.hasMoreElements())
452:                 v.addElement(e.nextElement());
453:         }
454:
455:         String[] f = new String[v.size()];
456:         v.copyInto(f);
457:         return f;
458: }
459:
460: /**
461: * Clear all of the system flags.
462: *
463: * @since        JavaMail 1.6
464: */
465: public void clearSystemFlags() {
466:         system_flags = 0;
467: }
468:
469: /**
470: * Clear all of the user flags.
471: *
472: * @since        JavaMail 1.6
473: */
474: public void clearUserFlags() {
475:         user_flags = null;
476: }
477:
478: /**
479: * Returns a clone of this Flags object.
480: */
481: @SuppressWarnings("unchecked")
482: @Override
483: public Object clone() {
484:         Flags f = null;
485:         try {
486:          f = (Flags)super.clone();
487:         } catch (CloneNotSupportedException cex) {
488:          // ignore, can't happen
489:         }
490:         if (this.user_flags != null)
491:          f.user_flags = (Hashtable)this.user_flags.clone();
492:         return f;
493: }
494:
495: /**
496: * Return a string representation of this Flags object.
497: * Note that the exact format of the string is subject to change.
498: */
499: public String toString() {
500:         StringBuilder sb = new StringBuilder();
501:
502:         if ((system_flags & ANSWERED_BIT) != 0)
503:          sb.append("\\Answered ");
504:         if ((system_flags & DELETED_BIT) != 0)
505:          sb.append("\\Deleted ");
506:         if ((system_flags & DRAFT_BIT) != 0)
507:          sb.append("\\Draft ");
508:         if ((system_flags & FLAGGED_BIT) != 0)
509:          sb.append("\\Flagged ");
510:         if ((system_flags & RECENT_BIT) != 0)
511:          sb.append("\\Recent ");
512:         if ((system_flags & SEEN_BIT) != 0)
513:          sb.append("\\Seen ");
514:         if ((system_flags & USER_BIT) != 0)
515:          sb.append("\\* ");
516:
517:         boolean first = true;
518:         if (user_flags != null) {
519:          Enumeration<String> e = user_flags.elements();
520:
521:          while (e.hasMoreElements()) {
522:                 if (first)
523:                  first = false;
524:                 else
525:                  sb.append(' ');
526:                 sb.append(e.nextElement());
527:          }
528:         }
529:
530:         if (first && sb.length() > 0)
531:          sb.setLength(sb.length() - 1);        // smash trailing space
532:
533:         return sb.toString();
534: }
535:
536: /*****
537: public static void main(String argv[]) throws Exception {
538:         // a new flags object
539:         Flags f1 = new Flags();
540:         f1.add(Flags.Flag.DELETED);
541:         f1.add(Flags.Flag.SEEN);
542:         f1.add(Flags.Flag.RECENT);
543:         f1.add(Flags.Flag.ANSWERED);
544:
545:         // check copy constructor with only system flags
546:         Flags fc = new Flags(f1);
547:         if (f1.equals(fc) && fc.equals(f1))
548:          System.out.println("success");
549:         else
550:          System.out.println("fail");
551:
552:         // check clone with only system flags
553:         fc = (Flags)f1.clone();
554:         if (f1.equals(fc) && fc.equals(f1))
555:          System.out.println("success");
556:         else
557:          System.out.println("fail");
558:
559:         // add a user flag and make sure it still works right
560:         f1.add("MyFlag");
561:
562:         // shouldn't be equal here
563:         if (!f1.equals(fc) && !fc.equals(f1))
564:          System.out.println("success");
565:         else
566:          System.out.println("fail");
567:
568:         // check clone
569:         fc = (Flags)f1.clone();
570:         if (f1.equals(fc) && fc.equals(f1))
571:          System.out.println("success");
572:         else
573:          System.out.println("fail");
574:
575:         // make sure user flag hash tables are separate
576:         fc.add("AnotherFlag");
577:         if (!f1.equals(fc) && !fc.equals(f1))
578:          System.out.println("success");
579:         else
580:          System.out.println("fail");
581:
582:         // check copy constructor
583:         fc = new Flags(f1);
584:         if (f1.equals(fc) && fc.equals(f1))
585:          System.out.println("success");
586:         else
587:          System.out.println("fail");
588:
589:         // another new flags object
590:         Flags f2 = new Flags(Flags.Flag.ANSWERED);
591:         f2.add("MyFlag");
592:
593:         if (f1.contains(Flags.Flag.DELETED))
594:          System.out.println("success");
595:         else
596:          System.out.println("fail");
597:                 
598:         if (f1.contains(Flags.Flag.SEEN))
599:          System.out.println("success");
600:         else
601:          System.out.println("fail");
602:
603:         if (f1.contains(Flags.Flag.RECENT))
604:          System.out.println("success");
605:         else
606:          System.out.println("fail");
607:
608:         if (f1.contains("MyFlag"))
609:          System.out.println("success");
610:         else
611:          System.out.println("fail");
612:
613:         if (f2.contains(Flags.Flag.ANSWERED))
614:          System.out.println("success");
615:         else
616:          System.out.println("fail");
617:
618:
619:         System.out.println("----------------");
620:
621:         String[] s = f1.getUserFlags();
622:         for (int i = 0; i < s.length; i++)
623:          System.out.println(s[i]);
624:         System.out.println("----------------");
625:         s = f2.getUserFlags();
626:         for (int i = 0; i < s.length; i++)
627:          System.out.println(s[i]);
628:
629:         System.out.println("----------------");
630:
631:         if (f1.contains(f2)) // this should be true
632:          System.out.println("success");
633:         else
634:          System.out.println("fail");
635:
636:         if (!f2.contains(f1)) // this should be false
637:          System.out.println("success");
638:         else
639:          System.out.println("fail");
640:
641:         Flags f3 = new Flags();
642:         f3.add(Flags.Flag.DELETED);
643:         f3.add(Flags.Flag.SEEN);
644:         f3.add(Flags.Flag.RECENT);
645:         f3.add(Flags.Flag.ANSWERED);
646:         f3.add("ANOTHERFLAG");
647:         f3.add("MYFLAG");
648:
649:         f1.add("AnotherFlag");
650:
651:         if (f1.equals(f3))
652:          System.out.println("equals success");
653:         else
654:          System.out.println("fail");
655:         if (f3.equals(f1))
656:          System.out.println("equals success");
657:         else
658:          System.out.println("fail");
659:         System.out.println("f1 hash code " + f1.hashCode());
660:         System.out.println("f3 hash code " + f3.hashCode());
661:         if (f1.hashCode() == f3.hashCode())
662:          System.out.println("success");
663:         else
664:          System.out.println("fail");
665: }
666: ****/
667: }