001 /*
002 * Copyright 2010 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package com.hs.mail.imap.message.builder;
017
018 import java.io.UnsupportedEncodingException;
019 import java.util.LinkedList;
020
021 import javax.mail.Flags;
022 import javax.mail.Message;
023 import javax.mail.internet.MimeUtility;
024 import javax.mail.search.ComparisonTerm;
025
026 import com.hs.mail.imap.message.SequenceRange;
027 import com.hs.mail.imap.message.request.ImapRequest;
028 import com.hs.mail.imap.message.request.SearchRequest;
029 import com.hs.mail.imap.message.search.AllKey;
030 import com.hs.mail.imap.message.search.AndKey;
031 import com.hs.mail.imap.message.search.FlagKey;
032 import com.hs.mail.imap.message.search.FromStringKey;
033 import com.hs.mail.imap.message.search.HeaderKey;
034 import com.hs.mail.imap.message.search.InternalDateKey;
035 import com.hs.mail.imap.message.search.KeywordKey;
036 import com.hs.mail.imap.message.search.NotKey;
037 import com.hs.mail.imap.message.search.OrKey;
038 import com.hs.mail.imap.message.search.RecipientStringKey;
039 import com.hs.mail.imap.message.search.SearchKey;
040 import com.hs.mail.imap.message.search.SearchKeyList;
041 import com.hs.mail.imap.message.search.SentDateKey;
042 import com.hs.mail.imap.message.search.SequenceKey;
043 import com.hs.mail.imap.message.search.SizeKey;
044 import com.hs.mail.imap.message.search.SubjectKey;
045 import com.hs.mail.imap.message.search.TextKey;
046 import com.hs.mail.imap.parser.ParseException;
047 import com.hs.mail.imap.parser.Token;
048 import com.hs.mail.imap.server.codec.DecoderUtils;
049 import com.hs.mail.imap.server.codec.ImapMessage;
050 import com.hs.mail.util.MailUtils;
051
052 /**
053 *
054 * @author Won Chul Doh
055 * @since 30 Jan, 2010
056 *
057 */
058 public class SearchRequestBuilder extends AbstractUidRequestBuilder {
059
060 @Override
061 public ImapRequest createRequest(String tag, String command,
062 ImapMessage message, boolean useUID) {
063 LinkedList<Token> tokens = message.getTokens();
064 String charset = parseCharset(tokens);
065 SearchKey searchKey = createSearchKey(tag, tokens, charset);
066 return new SearchRequest(tag, command, charset, searchKey, useUID);
067 }
068
069 protected SearchKey createSearchKey(String tag, LinkedList<Token> tokens,
070 String charset) {
071 try {
072 SearchKeyList searchKey = new AndKey();
073 do {
074 searchKey.addKey(decodeSearchKey(tokens, charset));
075 } while (tokens.peek() != null);
076 removeAllKey(searchKey);
077 if (searchKey.size() == 1) {
078 return searchKey.getSearchKeys().get(0);
079 } else {
080 return searchKey;
081 }
082 } catch (Exception e) {
083 throw new ParseException(tag, "Error while parsing command");
084 }
085 }
086
087 private void removeAllKey(SearchKeyList searchKey) {
088 if (searchKey.size() > 1) {
089 searchKey.getSearchKeys().remove(new AllKey());
090 }
091 }
092
093 protected String parseCharset(LinkedList<Token> tokens) {
094 Token token = tokens.peek();
095 if ("CHARSET".equals(token.value.toUpperCase())) {
096 tokens.remove();
097 return MimeUtility.javaCharset(tokens.remove().value);
098 } else {
099 return null;
100 }
101 }
102
103 private SearchKey decodeSearchKey(LinkedList<Token> tokens, String charset)
104 throws Exception {
105 Token token = tokens.peek();
106 SearchKey key = null;
107 if (token.type == Token.Type.KEYWORD) {
108 tokens.remove();
109 String value = token.value.toUpperCase();
110 if ("ALL".equals(value)) {
111 key = new AllKey();
112 } else if ("ANSWERED".equals(value)) {
113 key = new FlagKey(Flags.Flag.ANSWERED, true);
114 } else if ("BCC".equals(value)) {
115 key = new RecipientStringKey(Message.RecipientType.BCC, decode(
116 (token = tokens.remove()).value, charset));
117 } else if ("BEFORE".equals(value)) {
118 key = new InternalDateKey(ComparisonTerm.LT, DecoderUtils
119 .parseDate((token = tokens.remove()).value));
120 } else if ("BODY".equals(value)) {
121 key = new TextKey(decode((token = tokens.remove()).value,
122 charset), false);
123 } else if ("CC".equals(value)) {
124 key = new RecipientStringKey(Message.RecipientType.CC, decode(
125 (token = tokens.remove()).value, charset));
126 } else if ("DELETED".equals(value)) {
127 key = new FlagKey(Flags.Flag.DELETED, true);
128 } else if ("FLAGGED".equals(value)) {
129 key = new FlagKey(Flags.Flag.FLAGGED, true);
130 } else if ("FROM".equals(value)) {
131 key = new FromStringKey(decode((token = tokens.remove()).value,
132 charset));
133 } else if ("KEYWORD".equals(value)) {
134 key = new KeywordKey(decode((token = tokens.remove()).value,
135 charset), true);
136 } else if ("NEW".equals(value)) {
137 key = new AndKey(new FlagKey(Flags.Flag.RECENT, true),
138 new FlagKey(Flags.Flag.SEEN, false));
139 } else if ("OLD".equals(value)) {
140 key = new FlagKey(Flags.Flag.RECENT, false);
141 } else if ("ON".equals(value)) {
142 key = new InternalDateKey(ComparisonTerm.EQ, DecoderUtils
143 .parseDate((token = tokens.remove()).value));
144 } else if ("RECENT".equals(value)) {
145 key = new FlagKey(Flags.Flag.RECENT, true);
146 } else if ("SEEN".equals(value)) {
147 key = new FlagKey(Flags.Flag.SEEN, true);
148 } else if ("SINCE".equals(value)) {
149 key = new InternalDateKey(ComparisonTerm.GE, DecoderUtils
150 .parseDate((token = tokens.remove()).value));
151 } else if ("SUBJECT".equals(value)) {
152 key = new SubjectKey(decode((token = tokens.remove()).value,
153 charset));
154 } else if ("TEXT".equals(value)) {
155 key = new TextKey((token = tokens.remove()).value);
156 } else if ("TO".equals(value)) {
157 key = new RecipientStringKey(Message.RecipientType.TO, decode(
158 (token = tokens.remove()).value, charset));
159 } else if ("UNANSWERED".equals(value)) {
160 key = new FlagKey(Flags.Flag.ANSWERED, false);
161 } else if ("UNDELETED".equals(value)) {
162 key = new FlagKey(Flags.Flag.DELETED, false);
163 } else if ("UNFLAGGED".equals(value)) {
164 key = new FlagKey(Flags.Flag.FLAGGED, false);
165 } else if ("UNKEYWORD".equals(value)) {
166 key = new KeywordKey((token = tokens.remove()).value, false);
167 } else if ("UNSEEN".equals(value)) {
168 key = new FlagKey(Flags.Flag.SEEN, false);
169 } else if ("DRAFT".equals(value)) {
170 key = new FlagKey(Flags.Flag.DRAFT, true);
171 } else if ("HEADER".equals(value)) {
172 String headerName = tokens.remove().value;
173 key = new HeaderKey(headerName, (token = tokens.remove()).value);
174 } else if ("LARGER".equals(value)) {
175 key = new SizeKey(ComparisonTerm.GT, Integer
176 .parseInt((token = tokens.remove()).value));
177 } else if ("NOT".equals(value)) {
178 key = new NotKey(decodeSearchKey(tokens, charset));
179 } else if ("OR".equals(value)) {
180 SearchKey k1 = decodeSearchKey(tokens, charset);
181 SearchKey k2 = decodeSearchKey(tokens, charset);
182 key = new OrKey(k1, k2);
183 } else if ("SENTBEFORE".equals(value)) {
184 key = new SentDateKey(ComparisonTerm.LT, DecoderUtils
185 .parseDate((token = tokens.remove()).value));
186 } else if ("SENTON".equals(value)) {
187 key = new SentDateKey(ComparisonTerm.EQ, DecoderUtils
188 .parseDate((token = tokens.remove()).value));
189 } else if ("SENTSINCE".equals(value)) {
190 key = new SentDateKey(ComparisonTerm.GE, DecoderUtils
191 .parseDate((token = tokens.remove()).value));
192 } else if ("SMALLER".equals(value)) {
193 key = new SizeKey(ComparisonTerm.LT, Integer
194 .parseInt((token = tokens.remove()).value));
195 } else if ("UID".equals(value)) {
196 SequenceRange[] sequenceSet = parseSequenceSet(tokens);
197 key = new SequenceKey(sequenceSet, true);
198 } else if ("UNDRAFT".equals(value)) {
199 key = new FlagKey(Flags.Flag.DRAFT, false);
200 }
201 } else if (token.type == Token.Type.SEQ_NUMBER
202 || token.type == Token.Type.SEQ_RANGE) {
203 SequenceRange[] sequenceSet = parseSequenceSet(tokens);
204 key = new SequenceKey(sequenceSet);
205 } else if (token.type == Token.Type.LPAREN) {
206 tokens.remove();
207 key = new AndKey();
208 do {
209 if (token.type == Token.Type.RPAREN) {
210 tokens.remove();
211 break;
212 }
213 ((AndKey) key).addKey(decodeSearchKey(tokens, charset));
214 token = tokens.peek();
215 } while (true);
216 } else {
217 throw new Exception("Unexpected token: " + token);
218 }
219 return key;
220 }
221
222 private static String decode(String s, String charset) {
223 if (charset != null) {
224 try {
225 if (!MailUtils.isAscii(s) && !"ISO8859_1".equals(charset)) {
226 return new String(s.getBytes("ISO8859_1"), charset);
227 }
228 } catch (UnsupportedEncodingException e) {
229 }
230 }
231 return s;
232 }
233
234 }