2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 @interface EOQualifier(PrivateMethodes)
27 - (NSString *)qualifierDescription;
29 - (NSException *)invalidImap4SearchQualifier:(NSString *)_reason;
31 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search
32 insertNot:(BOOL)_insertNot;
36 @implementation EOQualifier(IMAPAdditions)
38 - (BOOL)isImap4UnseenQualifier {
42 /* building search qualifiers */
44 static NSArray *FlagKeyWords = nil;
45 static NSArray *OtherKeyWords = nil;
46 static BOOL debugOn = NO;
48 - (void)_initImap4SearchCategory {
51 if (FlagKeyWords) return;
53 ud = [NSUserDefaults standardUserDefaults];
54 FlagKeyWords = [[NSArray alloc] initWithObjects: @"answered", @"deleted",
55 @"draft", @"flagged", @"new", @"old", @"recent",
56 @"seen", @"unanswered", @"undeleted", @"undraft",
57 @"unflagged", @"unseen", nil];
58 OtherKeyWords = [[NSArray alloc] initWithObjects:
59 @"bcc", @"body", @"cc", @"from", @"subject",
60 @"text", @"to", @"keyword", @"unkeyword", nil];
62 debugOn = [ud boolForKey:@"ImapDebugQualifierGeneration"];
65 - (NSException *)invalidImap4SearchQualifier:(NSString *)_reason {
66 if (_reason == nil) _reason = @"unknown reason";
67 return [NSException exceptionWithName:@"NGImap4SearchQualifierException"
72 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
75 - (BOOL)isImap4NotQualifier {
78 - (BOOL)isImap4KeyValueQualifier {
82 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search
83 insertNot:(BOOL)_insertNot
85 return [self invalidImap4SearchQualifier:@"expected key/value qualifier"];
87 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search {
88 return [self appendToImap4SearchString:_search insertNot:NO];
91 - (id)imap4SearchString { /* returns exception on fail */
92 // TODO: split up method
93 BOOL disjunction = NO; /* OR */
96 NSMutableString *search;
98 [self _initImap4SearchCategory];
100 if ([self isImap4UnseenQualifier]) {
102 [self logWithFormat:@"is unseen: %@ (%@)", self, [self class]];
107 [self logWithFormat:@"generate IMAP4 expression for qualifier: %@", self];
109 search = [NSMutableString stringWithCapacity:256];
112 if ((quals = [self subqualifiersForImap4SearchString:&disjunction]) == nil) {
114 [self logWithFormat:@" got no subqualifiers .."];
116 return (id)[self invalidImap4SearchQualifier:@"unexpected qualifier 1"];
120 [search appendString:@" or"];
122 while ((qualifier = [quals nextObject])) {
126 [self logWithFormat:@" append subqualifier: %@", qualifier];
128 if ((error = [qualifier appendToImap4SearchString:search]))
133 [self logWithFormat:@" generated: '%@'", search];
138 @end /* EOQualifier(IMAPAdditions) */
140 @implementation EOAndQualifier(IMAPAdditions)
142 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
143 if (_isDisjunction) *_isDisjunction = NO;
144 return [[self qualifiers] objectEnumerator];
147 @end /* EOAndQualifier(IMAPAdditions) */
149 @implementation EOOrQualifier(IMAPAdditions)
151 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
152 if (_isDisjunction) *_isDisjunction = YES;
153 return [[self qualifiers] objectEnumerator];
156 @end /* EOOrQualifier(IMAPAdditions) */
158 @implementation EOKeyValueQualifier(IMAPAdditions)
160 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
161 if (_isDisjunction) *_isDisjunction = NO;
162 return [[NSArray arrayWithObject:self] objectEnumerator];
165 - (BOOL)isImap4KeyValueQualifier {
169 - (BOOL)isImap4UnseenQualifier {
170 // TODO: this is rather weird: flags suggests an array value!
171 if (![[self key] isEqualToString:@"flags"])
173 return [[self value] isEqualToString:@"unseen"];
176 - (NSException *)appendFlagsCheckToImap4SearchString:(NSMutableString *)search
177 insertNot:(BOOL)insertNot
179 NSEnumerator *enumerator = nil;
183 lvalue = [self value];
184 lselector = [self selector];
186 if (sel_eq(lselector, EOQualifierOperatorEqual)) {
187 lvalue = [NSArray arrayWithObject:lvalue];
189 else if (!sel_eq(lselector, EOQualifierOperatorContains)) {
190 return [self invalidImap4SearchQualifier:
191 @"unexpected EOKeyValueQualifier selector"];
193 if (![lvalue isKindOfClass:[NSArray class]]) {
194 return [self invalidImap4SearchQualifier:
195 @"expected an array in contains-qualifier"];
197 enumerator = [lvalue objectEnumerator];
198 while ((lvalue = [enumerator nextObject])) {
199 lvalue = [lvalue lowercaseString];
201 if ([FlagKeyWords containsObject:lvalue]) {
202 [search appendString:insertNot ? @" not " : @" "];
203 [search appendString:lvalue];
206 return [self invalidImap4SearchQualifier:
207 @"unexpected keyword for EOKeyValueQualifier"];
213 - (NSString *)imap4OperatorForDateComparisonSelector:(SEL)lselector {
214 if (sel_eq(lselector, EOQualifierOperatorEqual))
216 if (sel_eq(lselector, EOQualifierOperatorGreaterThan))
217 return @" sentsince ";
218 if (sel_eq(lselector, EOQualifierOperatorLessThan))
219 return @" sentbefore ";
224 - (NSException *)appendToImap4SearchString:(NSMutableString *)search
225 insertNot:(BOOL)insertNot
227 /* returns exception on fail */
232 lkey = [[self key] lowercaseString];
233 lvalue = [self value];
234 lselector = [self selector];
236 if ([lkey isEqualToString:@"flags"]) {
237 return [self appendFlagsCheckToImap4SearchString:search
238 insertNot:insertNot];
243 [search appendString:@" not"];
245 if ([lkey isEqualToString:@"date"]) {
248 if (![lvalue isKindOfClass:[NSCalendarDate class]]) {
249 return [self invalidImap4SearchQualifier:
250 @"expected a NSDate as value"];
253 if ((s = [self imap4OperatorForDateComparisonSelector:lselector]) == nil)
254 return [self invalidImap4SearchQualifier:@"unexpected selector"];
256 // TODO: much faster without descriptionWithCalendarFormat:?!
257 s = [lvalue descriptionWithCalendarFormat:@"%d-%b-%Y"];
258 [search appendString:s];
260 else if ([lkey isEqualToString:@"uid"]) {
261 if (!sel_eq(lselector, EOQualifierOperatorEqual))
262 return [self invalidImap4SearchQualifier:@"unexpected qualifier 2"];
264 [search appendString:@" uid "];
265 [search appendString:[lvalue stringValue]];
267 else if ([lkey isEqualToString:@"size"]) {
268 if (sel_eq(lselector, EOQualifierOperatorGreaterThan))
269 [search appendString:@" larger "];
270 else if (sel_eq(lselector, EOQualifierOperatorLessThan))
271 [search appendString:@" smaller "];
273 return [self invalidImap4SearchQualifier:@"unexpected qualifier 3"];
275 [search appendString:[lvalue stringValue]];
277 else if ([OtherKeyWords containsObject:lkey]) {
278 if (!sel_eq(lselector, EOQualifierOperatorEqual)) {
279 [self logWithFormat:@"SELECTOR: got: %@, allowed: %@",
280 NSStringFromSelector(lselector),
281 NSStringFromSelector(EOQualifierOperatorEqual)];
282 return [self invalidImap4SearchQualifier:
283 @"unexpected qualifier, disallowed comparison on "
287 [search appendString:@" "];
288 [search appendString:lkey];
289 [search appendString:@" \""];
290 [search appendString:[lvalue stringValue]];
291 [search appendString:@"\""];
294 if (!sel_eq(lselector, EOQualifierOperatorEqual))
295 return [self invalidImap4SearchQualifier:@"unexpected qualifier 5"];
297 [search appendString:@" header "];
298 [search appendString:lkey];
299 [search appendString:@" \""];
300 [search appendString:[lvalue stringValue]];
301 [search appendString:@"\""];
306 @end /* EOKeyValueQualifier(IMAPAdditions) */
308 @implementation EONotQualifier(IMAPAdditions)
310 - (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
311 if (_isDisjunction) *_isDisjunction = NO;
312 return [[NSArray arrayWithObject:self] objectEnumerator];
315 - (BOOL)isImap4NotQualifier {
319 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search {
320 return [[self qualifier] appendToImap4SearchString:_search insertNot:YES];
323 @end /* EONotQualifier(IMAPAdditions) */