2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 @interface EOQualifier(PrivateMethodes)
26 - (NSString *)qualifierDescription;
28 - (NSException *)invalidImap4SearchQualifier:(NSString *)_reason;
30 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search
31 insertNot:(BOOL)_insertNot;
35 @implementation EOQualifier(IMAPAdditions)
37 - (BOOL)isImap4UnseenQualifier {
41 /* building search qualifiers */
43 static NSArray *FlagKeyWords = nil;
44 static NSArray *OtherKeyWords = nil;
45 static BOOL debugOn = NO;
47 - (void)_initImap4SearchCategory {
50 if (FlagKeyWords) return;
52 ud = [NSUserDefaults standardUserDefaults];
53 FlagKeyWords = [[NSArray alloc] initWithObjects: @"answered", @"deleted",
54 @"draft", @"flagged", @"new", @"old", @"recent",
55 @"seen", @"unanswered", @"undeleted", @"undraft",
56 @"unflagged", @"unseen", nil];
57 OtherKeyWords = [[NSArray alloc] initWithObjects:
58 @"bcc", @"body", @"cc", @"from", @"subject",
59 @"text", @"to", @"keyword", @"unkeyword", nil];
61 debugOn = [ud boolForKey:@"ImapDebugQualifierGeneration"];
64 - (NSException *)invalidImap4SearchQualifier:(NSString *)_reason {
65 if (_reason == nil) _reason = @"unknown reason";
66 return [NSException exceptionWithName:@"NGImap4SearchQualifierException"
71 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
74 - (BOOL)isImap4NotQualifier {
77 - (BOOL)isImap4KeyValueQualifier {
81 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search
82 insertNot:(BOOL)_insertNot
84 return [self invalidImap4SearchQualifier:@"expected key/value qualifier"];
86 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search {
87 return [self appendToImap4SearchString:_search insertNot:NO];
90 - (id)imap4SearchString { /* returns exception on fail */
91 // TODO: split up method
92 BOOL disjunction = NO; /* OR */
95 NSMutableString *search;
97 [self _initImap4SearchCategory];
99 if ([self isImap4UnseenQualifier]) {
101 [self logWithFormat:@"is unseen: %@ (%@)", self, [self class]];
106 [self logWithFormat:@"generate IMAP4 expression for qualifier: %@", self];
108 search = [NSMutableString stringWithCapacity:256];
111 if ((quals = [self subqualifiersForImap4SearchString:&disjunction]) == nil) {
113 [self logWithFormat:@" got no subqualifiers .."];
115 return (id)[self invalidImap4SearchQualifier:@"unexpected qualifier 1"];
119 [search appendString:@" or"];
121 while ((qualifier = [quals nextObject]) != nil) {
125 [self logWithFormat:@" append subqualifier: %@", qualifier];
127 if ((error = [qualifier appendToImap4SearchString:search]))
132 [self logWithFormat:@" generated: '%@'", search];
137 @end /* EOQualifier(IMAPAdditions) */
139 @implementation EOAndQualifier(IMAPAdditions)
141 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
142 if (_isDisjunction) *_isDisjunction = NO;
143 return [[self qualifiers] objectEnumerator];
146 @end /* EOAndQualifier(IMAPAdditions) */
148 @implementation EOOrQualifier(IMAPAdditions)
150 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
151 if (_isDisjunction) *_isDisjunction = YES;
152 return [[self qualifiers] objectEnumerator];
155 @end /* EOOrQualifier(IMAPAdditions) */
157 @implementation EOKeyValueQualifier(IMAPAdditions)
159 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
160 if (_isDisjunction) *_isDisjunction = NO;
161 return [[NSArray arrayWithObject:self] objectEnumerator];
164 - (BOOL)isImap4KeyValueQualifier {
168 - (BOOL)isImap4UnseenQualifier {
169 // TODO: this is rather weird: flags suggests an array value!
170 if (![[self key] isEqualToString:@"flags"])
172 return [[self value] isEqualToString:@"unseen"];
175 - (NSException *)appendFlagsCheckToImap4SearchString:(NSMutableString *)search
176 insertNot:(BOOL)insertNot
178 NSEnumerator *enumerator = nil;
182 lvalue = [self value];
183 lselector = [self selector];
185 if (sel_eq(lselector, EOQualifierOperatorEqual)) {
186 lvalue = [NSArray arrayWithObject:lvalue];
188 else if (!sel_eq(lselector, EOQualifierOperatorContains)) {
189 return [self invalidImap4SearchQualifier:
190 @"unexpected EOKeyValueQualifier selector"];
192 if (![lvalue isKindOfClass:[NSArray class]]) {
193 return [self invalidImap4SearchQualifier:
194 @"expected an array in contains-qualifier"];
196 enumerator = [lvalue objectEnumerator];
197 while ((lvalue = [enumerator nextObject])) {
198 lvalue = [lvalue lowercaseString];
200 if ([FlagKeyWords containsObject:lvalue]) {
201 [search appendString:insertNot ? @" not " : @" "];
202 [search appendString:lvalue];
205 return [self invalidImap4SearchQualifier:
206 @"unexpected keyword for EOKeyValueQualifier"];
212 - (NSString *)imap4OperatorForDateComparisonSelector:(SEL)lselector {
213 if (sel_eq(lselector, EOQualifierOperatorEqual))
215 if (sel_eq(lselector, EOQualifierOperatorGreaterThan))
216 return @" sentsince ";
217 if (sel_eq(lselector, EOQualifierOperatorLessThan))
218 return @" sentbefore ";
223 - (NSException *)appendToImap4SearchString:(NSMutableString *)search
224 insertNot:(BOOL)insertNot
226 /* returns exception on fail */
231 lkey = [[self key] lowercaseString];
232 lvalue = [self value];
233 lselector = [self selector];
235 if ([lkey isEqualToString:@"flags"]) {
236 return [self appendFlagsCheckToImap4SearchString:search
237 insertNot:insertNot];
242 [search appendString:@" not"];
244 if ([lkey isEqualToString:@"date"]) {
247 if (![lvalue isKindOfClass:[NSCalendarDate class]]) {
248 return [self invalidImap4SearchQualifier:
249 @"expected a NSDate as value"];
252 if ((s = [self imap4OperatorForDateComparisonSelector:lselector]) == nil)
253 return [self invalidImap4SearchQualifier:@"unexpected selector"];
255 // TODO: much faster without descriptionWithCalendarFormat:?!
256 s = [lvalue descriptionWithCalendarFormat:@"%d-%b-%Y"];
257 [search appendString:s];
259 else if ([lkey isEqualToString:@"uid"]) {
260 if (!sel_eq(lselector, EOQualifierOperatorEqual))
261 return [self invalidImap4SearchQualifier:@"unexpected qualifier 2"];
263 [search appendString:@" uid "];
264 [search appendString:[lvalue stringValue]];
266 else if ([lkey isEqualToString:@"size"]) {
267 if (sel_eq(lselector, EOQualifierOperatorGreaterThan))
268 [search appendString:@" larger "];
269 else if (sel_eq(lselector, EOQualifierOperatorLessThan))
270 [search appendString:@" smaller "];
272 return [self invalidImap4SearchQualifier:@"unexpected qualifier 3"];
274 [search appendString:[lvalue stringValue]];
276 else if ([OtherKeyWords containsObject:lkey]) {
277 // TODO: actually most keywords only allow for contains! Eg "subject abc"
278 // is a contains query, not an equal query!
279 if (!sel_eq(lselector, EOQualifierOperatorEqual) &&
280 !sel_eq(lselector, EOQualifierOperatorContains)) {
281 [self logWithFormat:@"IMAP4 generation: got: %@, allowed: %@",
282 NSStringFromSelector(lselector),
283 NSStringFromSelector(EOQualifierOperatorEqual)];
284 return [self invalidImap4SearchQualifier:
285 @"unexpected qualifier, disallowed comparison on "
289 [search appendString:@" "];
290 [search appendString:lkey];
291 [search appendString:@" \""];
292 [search appendString:[lvalue stringValue]];
293 [search appendString:@"\""];
296 if (!sel_eq(lselector, EOQualifierOperatorEqual))
297 return [self invalidImap4SearchQualifier:@"unexpected qualifier 5"];
299 [search appendString:@" header "];
300 [search appendString:lkey];
301 [search appendString:@" \""];
302 [search appendString:[lvalue stringValue]];
303 [search appendString:@"\""];
308 @end /* EOKeyValueQualifier(IMAPAdditions) */
310 @implementation EONotQualifier(IMAPAdditions)
312 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
313 if (_isDisjunction) *_isDisjunction = NO;
314 return [[NSArray arrayWithObject:self] objectEnumerator];
317 - (BOOL)isImap4NotQualifier {
321 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search {
322 return [[self qualifier] appendToImap4SearchString:_search insertNot:YES];
325 @end /* EONotQualifier(IMAPAdditions) */