reshuffling of file locations to make package structure flatter
[org.ibex.mail.git] / src / org / ibex / mail / Query.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.mail;
6 import java.util.*;
7 import org.ibex.mail.target.*;
8 import org.ibex.util.*;
9
10 /**
11  *  [immutable] This class encapsulates a query against a mailbox.
12  *
13  *  The default implementation of Mailbox.query() simply retrieves
14  *  each message and calls Query.match() on it to filter out any
15  *  messages which do not match.
16  *
17  *  Production-quality Mailbox implementations will want to inspect
18  *  the Query object passed to Mailbox.query() to perform more
19  *  efficient queries.
20  */
21 public class Query {
22
23     public static Query not(Query q)                { return new Query(NOT, new Query[] { q },0,0,0,null,null,null,null,null); }
24     public static Query and(Query q1, Query q2)     { return new Query(AND,new Query[]{q1,q2},0,0,0,null,null,null,null,null); }
25     public static Query and(Query[] q)              { return new Query(AND, q,0,0,0,null, null, null, null, null ); }
26     public static Query or(Query q1, Query q2)      { return new Query(OR,new Query[] {q1,q2},0,0,0,null,null, null, null, null); }
27     public static Query or(Query[] q)               { return new Query(OR, q, 0, 0, 0, null, null, null, null, null); }
28     public static Query uid(int min, int max)       { return new Query(UID, null, min, max, 0, null, null, null, null, null); }
29     public static Query imapNumber(int min,int max) { return new Query(IMAPNUM,null,min,max,0,null,null,null,null, null); }
30     public static Query nntpNumber(int min,int max) { return new Query(NNTPNUM,null,min,max,0,null,null,null,null, null); }
31     public static Query sent(Date e, Date l)        { return new Query(SENT,null,0,0,0,null,null,e,l,null); }
32     public static Query arrival(Date e, Date l)     { return new Query(ARRIVAL,null,0,0,0,null,null, e,l,null);}
33     public static Query header(String k, String v)  { return new Query(HEADER, null, 0, 0, 0, k, v, null, null, null);}
34     public static Query size(int min, int max)      { return new Query(SIZE, null, min, max, 0, null, null, null, null, null);}
35     public static Query body(String text)           { return new Query(BODY, null, 0, 0, 0, null, text, null, null, null);}
36     public static Query full(String text)           { return new Query(FULL, null, 0, 0, 0, null, text, null, null, null);}
37     public static Query uid(int[] set)              { return new Query(UID,  null, 0 ,0 ,0, null, null, null, null, set);}
38     public static Query imapNumber(int[] set)       { return new Query(IMAPNUM,  null, 0 ,0 ,0, null, null, null, null, set);}
39     public static Query all()                       { return new Query(ALL, null, 0, 0, 0, null, null, null, null, null); }
40     public static Query deleted()                   { return new Query(DELETED, null, 0, 0, 0, null, null, null, null, null); }
41     public static Query seen()                      { return new Query(SEEN, null, 0, 0, 0, null, null, null, null, null); }
42     public static Query flagged()                   { return new Query(FLAGGED, null, 0, 0, 0, null, null, null, null, null); }
43     public static Query draft()                     { return new Query(DRAFT, null, 0, 0, 0, null, null, null, null, null); }
44     public static Query answered()                  { return new Query(ANSWERED, null, 0, 0, 0, null, null, null, null, null); }
45     public static Query recent()                    { return new Query(RECENT, null, 0, 0, 0, null, null, null, null, null); }
46     //public static Query set(boolean uid, int[] set) { return uid ? uid(set) : imapNumber(set); }
47
48     private Query(int type, Query[] q,int min,int max, int flags, String key, String text, Date earliest, Date latest, int[] set) {
49         this.type = type; this.q = q; this.min = min; this.max = max; this.flags = flags; this.key = key; this.text = text;
50         this.earliest = earliest; this.latest = latest; this.set = set; }
51
52     public static final int ALL        = 0;
53     public static final int NOT        = 1;
54     public static final int AND        = 2;
55     public static final int OR         = 3;
56     public static final int UID        = 4;
57     public static final int SENT       = 5;
58     public static final int ARRIVAL    = 6;
59     public static final int HEADER     = 7;
60     public static final int SIZE       = 8;
61     public static final int BODY       = 9;
62     public static final int FULL       = 10;
63     public static final int IMAPNUM    = 11;
64     public static final int DELETED    = 12;
65     public static final int SEEN       = 13;
66     public static final int FLAGGED    = 14;
67     public static final int DRAFT      = 15;
68     public static final int ANSWERED   = 16;
69     public static final int RECENT     = 17;
70     public static final int NNTPNUM    = 18;
71
72     public final int type;
73     public final Query[] q;
74     public final int min;
75     public final int max;
76     public final int flags;
77     public final String key;
78     public final String text;
79     public final Date earliest;
80     public final Date latest;
81     public final int[] set;
82
83     public boolean match(Mailbox.Iterator it) {
84         switch(type) {
85             case ALL:        return true;
86             case NOT:        return !q[0].match(it);
87             case OR:         for(int i=0; i<q.length; i++) if (q[i].match(it)) return true; return false;
88             case AND:        for(int i=0; i<q.length; i++) if (!q[i].match(it)) return false; return true;
89             case UID:        if (set != null) {
90                                  for(int i=0; i<set.length; i+=2)
91                                      if (set[i] <= it.uid() && set[i+1] >= it.uid()) return true;
92                                  return false; }
93                              else return it.uid() >= min && it.uid() <= max;
94             case IMAPNUM:    if (set != null) {
95                                  for(int i=0; i<set.length; i+=2) if (set[i] <= it.imapNumber() && set[i+1] >= it.imapNumber()) return true;
96                                  return false; }
97                              else return it.imapNumber() >= min && it.imapNumber() <= max;
98             case NNTPNUM:    if (set != null) {
99                                  for(int i=0; i<set.length; i+=2) if (set[i] <= it.nntpNumber() && set[i+1] >= it.nntpNumber()) return true;
100                                  return false; }
101                              else return it.imapNumber() >= min && it.imapNumber() <= max;
102             case SENT:       return (latest==null||it.cur().date.before(latest)) && 
103                                     (earliest==null||it.cur().date.after(earliest));
104             case ARRIVAL:    return (latest == null || it.cur().arrival.before(latest)) &&
105                                     (earliest == null || it.cur().arrival.after(earliest));
106             case HEADER:     return it.cur().headers.get(key) != null &&
107                                  ((String)it.cur().headers.get(key)).toLowerCase().indexOf(text.toLowerCase()) != -1;
108             case DELETED:    return (it.getFlags() & Mailbox.Flag.DELETED) !=0;
109             case SEEN:       return (it.getFlags() & Mailbox.Flag.SEEN)!=0;
110             case FLAGGED:    return (it.getFlags() & Mailbox.Flag.FLAGGED)!=0;
111             case DRAFT:      return (it.getFlags() & Mailbox.Flag.DRAFT)!=0;
112             case ANSWERED:   return (it.getFlags() & Mailbox.Flag.ANSWERED)!=0;
113             case RECENT:     return (it.getFlags() & Mailbox.Flag.RECENT)!=0;
114
115             // FIXME: super inefficient
116             case BODY:       throw new RuntimeException("BODY searches are not supported because they are slow");
117             case FULL:       throw new RuntimeException("FULL searches are not supported because they are slow");
118             case SIZE:       throw new RuntimeException("SIZE searches are not supported because Adam is lame");
119                 //return it.cur().size() >= min && it.cur().size() <= max;
120
121             default:         throw new Error("this should not happen");
122         }
123     }
124 }