]> err.no Git - sope/commitdiff
fixed to qualifier handling
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sat, 12 Feb 2005 20:39:08 +0000 (20:39 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sat, 12 Feb 2005 20:39:08 +0000 (20:39 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@553 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-mime/ChangeLog
sope-mime/NGImap4/ChangeLog
sope-mime/NGImap4/EOQualifier+IMAPAdditions.m
sope-mime/NGImap4/NGImap4Client.m
sope-mime/Version

index a7453572f26870885ebb8d17fbd56bd6f6838c30..aeaf6f9fa57a1da1782930c75496eb61a9a321fc 100644 (file)
@@ -1,5 +1,8 @@
 2005-02-12  Helge Hess  <helge.hess@opengroupware.org>
 
+       * NGImap4: reworked qualifier generation, fixed handling of OR
+         qualifiers (v4.5.213)
+
        * NGImap4: improved copying, cleaned up sort ordering (v4.5.212)
 
 2005-02-08  Helge Hess  <helge.hess@opengroupware.org>
index bcbc6932eb8b832db383e570b4f02440bdf8b511..672d3273b0298f67fe9752946a333c85eebcc7f3 100644 (file)
@@ -1,5 +1,8 @@
 2005-02-12  Helge Hess  <helge.hess@opengroupware.org>
 
+       * EOQualifier+IMAPAdditions.m: more reworks in qualifier generation,
+         changed handling of spaces, fixed handling of OR qualifiers
+
        * EOQualifier+IMAPAdditions.m: allow contains: qualifier operator for
          key searches
 
index 401d4c02e6a81efa7c1b403ee38c747c9528dc11..9563b221f71a01946ed73e46570db8ce1ff5cad7 100644 (file)
 
 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search 
   insertNot:(BOOL)_insertNot;
+- (NSException *)appendToImap4SearchString:(NSMutableString *)_search;
 
 @end
 
 @implementation EOQualifier(IMAPAdditions)
 
-- (BOOL)isImap4UnseenQualifier {
+- (BOOL)isImap4UnseenQualifier { /* a special key/value qualifier */
   return NO;
 }
 
@@ -44,7 +45,7 @@ static NSArray *FlagKeyWords = nil;
 static NSArray *OtherKeyWords = nil;
 static BOOL    debugOn = NO;
 
-- (void)_initImap4SearchCategory {
+static void _initImap4SearchCategory(void) {
   NSUserDefaults *ud;
   
   if (FlagKeyWords) return;
@@ -68,9 +69,6 @@ static BOOL    debugOn = NO;
                       userInfo:nil];
 }
 
-- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
-  return nil;
-}
 - (BOOL)isImap4NotQualifier {
   return NO;
 }
@@ -88,44 +86,69 @@ static BOOL    debugOn = NO;
 }
 
 - (id)imap4SearchString { /* returns exception on fail */
-  // TODO: split up method
-  BOOL            disjunction = NO; /* OR */
-  NSEnumerator    *quals;
-  id              qualifier;
-  NSMutableString *search;
+  [self logWithFormat:@"ERROR(%s): subclass %@ must overide this method!",
+       __PRETTY_FUNCTION__, [self class]];
+  return nil;
+}
+
+@end /* EOQualifier(IMAPAdditions) */
+
+
+@implementation EOAndQualifier(IMAPAdditions)
+
+- (NSException *)appendToImap4SearchString:(NSMutableString *)_search {
+  NSArray         *quals;
+  unsigned        i, lCount;
   
-  [self _initImap4SearchCategory];
+  quals  = [self qualifiers];
   
-  if ([self isImap4UnseenQualifier]) {
+  if ((lCount = [quals count]) == 0) /* no subqualifiers */
+    return nil;
+  if (lCount == 1) {
+    // TODO: use appendToImap4SearchString?
+    [_search appendString:[[quals objectAtIndex:0] imap4SearchString]];
+    return nil;
+  }
+  
+  for (i = 0; i < lCount; i++) {
+    EOQualifier *qualifier;
+    NSException *error;
+    
+    qualifier = [quals objectAtIndex:i];
     if (debugOn)
-      [self logWithFormat:@"is unseen: %@ (%@)", self, [self class]];
-    return @" unseen";
+      [self logWithFormat:@"  append subqualifier: %@", qualifier];
+    
+    [_search appendString:(i == 0) ? @"(" : @" ("];
+    if ((error = [qualifier appendToImap4SearchString:_search]))
+      return error;
+    [_search appendString:@")"];
   }
   
-  if (debugOn)
-    [self logWithFormat:@"generate IMAP4 expression for qualifier: %@", self];
+  return nil /* no error */;
+}
+
+- (id)imap4SearchString { /* returns exception on fail */
+  NSMutableString *search;
+  NSException     *error;
+  unsigned        lCount;
   
-  search = [NSMutableString stringWithCapacity:256];
-  quals  = nil;
+  _initImap4SearchCategory();
   
-  if ((quals = [self subqualifiersForImap4SearchString:&disjunction]) == nil) {
-    if (debugOn)
-      [self logWithFormat:@"  got no subqualifiers .."];
-    
-    return (id)[self invalidImap4SearchQualifier:@"unexpected qualifier 1"];
+  if (debugOn) {
+    [self logWithFormat:
+           @"generate IMAP4 expression for AND qualifier: %@", self];
   }
   
-  if (disjunction)
-    [search appendString:@" or"];
+  if ((lCount = [[self qualifiers] count]) == 0) /* no subqualifiers */
+    return nil;
+  if (lCount == 1)
+    return [[[self qualifiers] objectAtIndex:0] imap4SearchString];
   
-  while ((qualifier = [quals nextObject]) != nil) {
-    NSException *error;
-
-    if (debugOn)
-      [self logWithFormat:@"  append subqualifier: %@", qualifier];
-    
-    if ((error = [qualifier appendToImap4SearchString:search]))
-      return error;
+  search = [NSMutableString stringWithCapacity:lCount * 3];
+  
+  if ((error = [self appendToImap4SearchString:search]) != nil) {
+    if (debugOn) [self logWithFormat:@"  error: %@", error];
+    return error;
   }
   
   if (debugOn)
@@ -134,32 +157,75 @@ static BOOL    debugOn = NO;
   return search;
 }
 
-@end /* EOQualifier(IMAPAdditions) */
+@end /* EOAndQualifier(IMAPAdditions) */
 
-@implementation EOAndQualifier(IMAPAdditions)
 
-- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
-  if (_isDisjunction) *_isDisjunction = NO;
-  return [[self qualifiers] objectEnumerator];
-}
+@implementation EOOrQualifier(IMAPAdditions)
 
-@end /* EOAndQualifier(IMAPAdditions) */
+- (NSException *)appendToImap4SearchString:(NSMutableString *)_search {
+  // TODO: move generation to this method
+  id s;
+  
+  s = [self imap4SearchString];
+  if ([s isKindOfClass:[NSException class]])
+    return s;
+  
+  [_search appendString:s];
+  return nil;
+}
 
-@implementation EOOrQualifier(IMAPAdditions)
+- (id)imap4SearchString { /* returns exception on fail */
+  NSArray         *quals;
+  NSMutableString *search;
+  unsigned        i, lCount;
+  NSException     *error;
+  
+  _initImap4SearchCategory();
+  
+  if (debugOn) {
+    [self logWithFormat:
+           @"generate IMAP4 expression for or-qualifier: %@", self];
+  }
+  
+  quals = [self qualifiers];
 
-- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
-  if (_isDisjunction) *_isDisjunction = YES;
-  return [[self qualifiers] objectEnumerator];
+  if ((lCount = [quals count]) == 0) /* no subqualifiers */
+    return nil;
+  if (lCount == 1)
+    return [[quals objectAtIndex:0] imap4SearchString];
+  
+  search = [NSMutableString stringWithCapacity:lCount * 32];
+  
+  /*
+    Note: or queries are specified as:
+            OR <search-key1> <search-key2>
+          so we need to wrap more ORs in multiple "OR" IMAP4 expressions
+          eg: "OR (OR (subject "abc") (subject "nbc")) from "duck""
+  */
+  
+  if ((error = [[quals objectAtIndex:0] appendToImap4SearchString:search]))
+    return error;
+  
+  for (i = 1; i < lCount; i++) {
+    EOQualifier *qualifier;
+    
+    qualifier = [quals objectAtIndex:i];
+    [search insertString:@"OR (" atIndex:0];
+    [search appendString:@") ("];
+    if ((error = [qualifier appendToImap4SearchString:search]))
+      return error;
+    [search appendString:@")"];
+  }
+  
+  if (debugOn)
+    [self logWithFormat:@"  generated: '%@'", search];
+  return search;
 }
 
 @end /* EOOrQualifier(IMAPAdditions) */
 
-@implementation EOKeyValueQualifier(IMAPAdditions)
 
-- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
-  if (_isDisjunction) *_isDisjunction = NO;
-  return [[NSArray arrayWithObject:self] objectEnumerator];
-}
+@implementation EOKeyValueQualifier(IMAPAdditions)
 
 - (BOOL)isImap4KeyValueQualifier {
   return YES;
@@ -182,31 +248,32 @@ static BOOL    debugOn = NO;
   lvalue    = [self value];
   lselector = [self selector];
       
-      if (sel_eq(lselector, EOQualifierOperatorEqual)) {
-        lvalue = [NSArray arrayWithObject:lvalue];
-      }
-      else if (!sel_eq(lselector, EOQualifierOperatorContains)) {
-        return [self invalidImap4SearchQualifier:
-                       @"unexpected EOKeyValueQualifier selector"];
-      }
-      if (![lvalue isKindOfClass:[NSArray class]]) {
-        return [self invalidImap4SearchQualifier:
-                       @"expected an array in contains-qualifier"];
-      }
-      enumerator = [lvalue objectEnumerator];
-      while ((lvalue = [enumerator nextObject])) {
-        lvalue = [lvalue lowercaseString];
+  if (sel_eq(lselector, EOQualifierOperatorEqual)) {
+    lvalue = [NSArray arrayWithObject:lvalue];
+  }
+  else if (!sel_eq(lselector, EOQualifierOperatorContains)) {
+    return [self invalidImap4SearchQualifier:
+                  @"unexpected EOKeyValueQualifier selector"];
+  }
+  if (![lvalue isKindOfClass:[NSArray class]]) {
+    return [self invalidImap4SearchQualifier:
+                  @"expected an array in contains-qualifier"];
+  }
+  
+  enumerator = [lvalue objectEnumerator];
+  while ((lvalue = [enumerator nextObject]) != nil) {
+    lvalue = [lvalue lowercaseString];
         
-        if ([FlagKeyWords containsObject:lvalue]) {
-         [search appendString:insertNot ? @" not " : @" "];
-          [search appendString:lvalue];
-        }
-        else {
-          return [self invalidImap4SearchQualifier:
-                         @"unexpected keyword for EOKeyValueQualifier"];
-       }
-      }
-      return nil;
+    if ([FlagKeyWords containsObject:lvalue]) {
+      if (insertNot) [search appendString:@"not "];
+      [search appendString:lvalue];
+    }
+    else {
+      return [self invalidImap4SearchQualifier:
+                    @"unexpected keyword for EOKeyValueQualifier"];
+    }
+  }
+  return nil;
 }
 
 - (NSString *)imap4OperatorForDateComparisonSelector:(SEL)lselector {
@@ -223,6 +290,7 @@ static BOOL    debugOn = NO;
 - (NSException *)appendToImap4SearchString:(NSMutableString *)search 
   insertNot:(BOOL)insertNot
 {
+  // TODO: this needs to get reworked
   /* returns exception on fail */
   NSString *lkey;
   id       lvalue;
@@ -233,13 +301,14 @@ static BOOL    debugOn = NO;
   lselector = [self selector];
     
   if ([lkey isEqualToString:@"flags"]) {
+    /* NOTE: special "not" processing! */
     return [self appendFlagsCheckToImap4SearchString:search 
                  insertNot:insertNot];
   }
   
   /* not a flag */
   if (insertNot) 
-    [search appendString:@" not"];
+    [search appendString:@"not "];
   
   if ([lkey isEqualToString:@"date"]) {
     NSString *s;
@@ -252,30 +321,46 @@ static BOOL    debugOn = NO;
     if ((s = [self imap4OperatorForDateComparisonSelector:lselector]) == nil)
       return [self invalidImap4SearchQualifier:@"unexpected selector"];
     
+    // TODO: operator created but NOT added?
+    
     // TODO: much faster without descriptionWithCalendarFormat:?!
     s = [lvalue descriptionWithCalendarFormat:@"%d-%b-%Y"];
     [search appendString:s];
+    return nil;
   }
-  else if ([lkey isEqualToString:@"uid"]) {
+
+  if ([lkey isEqualToString:@"uid"]) {
     if (!sel_eq(lselector, EOQualifierOperatorEqual))
       return [self invalidImap4SearchQualifier:@"unexpected qualifier 2"];
     
-    [search appendString:@" uid "];
+    [search appendString:@"uid "];
     [search appendString:[lvalue stringValue]];
+    return nil;
   }
-  else if ([lkey isEqualToString:@"size"]) {
+  
+  if ([lkey isEqualToString:@"size"]) {
     if (sel_eq(lselector, EOQualifierOperatorGreaterThan))
-      [search appendString:@" larger "];
+      [search appendString:@"larger "];
     else if (sel_eq(lselector, EOQualifierOperatorLessThan))
-      [search appendString:@" smaller "];
+      [search appendString:@"smaller "];
     else
       return [self invalidImap4SearchQualifier:@"unexpected qualifier 3"];
         
     [search appendString:[lvalue stringValue]];
+    return nil;
   }
-  else if ([OtherKeyWords containsObject:lkey]) {
+  
+  if ([OtherKeyWords containsObject:lkey]) {
     // TODO: actually most keywords only allow for contains! Eg "subject abc"
     //       is a contains query, not an equal query!
+    /*
+       RFC 3501:
+       In all search keys that use strings, a message matches the key if
+       the string is a substring of the field.  The matching is
+       case-insensitive.
+
+       Would be: "a caseInsensitiveLike: '*ABC*'"
+    */
     if (!sel_eq(lselector, EOQualifierOperatorEqual) &&
        !sel_eq(lselector, EOQualifierOperatorContains)) {
       [self logWithFormat:@"IMAP4 generation: got: %@, allowed: %@", 
@@ -286,40 +371,74 @@ static BOOL    debugOn = NO;
                     @"OtherKeyWords)"];
     }
     
-    [search appendString:@" "];
-    [search appendString:lkey];
-    [search appendString:@" \""];
-    [search appendString:[lvalue stringValue]];
-    [search appendString:@"\""];
-  }
-  else {
-    if (!sel_eq(lselector, EOQualifierOperatorEqual))
-      return [self invalidImap4SearchQualifier:@"unexpected qualifier 5"];
-    
-    [search appendString:@" header "];
     [search appendString:lkey];
     [search appendString:@" \""];
     [search appendString:[lvalue stringValue]];
     [search appendString:@"\""];
+    return nil;
   }
+  
+  
+  if (!sel_eq(lselector, EOQualifierOperatorEqual))
+    return [self invalidImap4SearchQualifier:@"unexpected qualifier 5"];
+  
+  [search appendString:@"header "];
+  [search appendString:lkey];
+  [search appendString:@" \""];
+  [search appendString:[lvalue stringValue]];
+  [search appendString:@"\""];
   return nil;
 }
 
+- (id)imap4SearchString { /* returns exception on fail */
+  NSMutableString *search;
+  NSException     *error;
+  
+  _initImap4SearchCategory();
+
+  if ([self isImap4UnseenQualifier]) {
+    if (debugOn)
+      [self logWithFormat:@"is unseen: %@ (%@)", self, [self class]];
+    return @"unseen";
+  }
+  
+  search = [NSMutableString stringWithCapacity:256];
+  
+  if ((error = [self appendToImap4SearchString:search]))
+    return error;
+  
+  return search;
+}
+
 @end /* EOKeyValueQualifier(IMAPAdditions) */
 
-@implementation EONotQualifier(IMAPAdditions)
 
-- (NSEnumerator *)subqualifiersForImap4SearchString:(BOOL *)_isDisjunction {
-  if (_isDisjunction) *_isDisjunction = NO;
-  return [[NSArray arrayWithObject:self] objectEnumerator];
-}
+@implementation EONotQualifier(IMAPAdditions)
 
 - (BOOL)isImap4NotQualifier {
   return YES;
 }
 
 - (NSException *)appendToImap4SearchString:(NSMutableString *)_search { 
+  /*
+    TODO: we do this because the key/value qualifier can generate multiple
+          queries
+  */
   return [[self qualifier] appendToImap4SearchString:_search insertNot:YES];
 }
 
+- (id)imap4SearchString { /* returns exception on fail */
+  NSMutableString *search;
+  NSException     *error;
+  
+  _initImap4SearchCategory();
+  
+  search = [NSMutableString stringWithCapacity:256];
+  
+  if ((error = [self appendToImap4SearchString:search]))
+    return error;
+  
+  return search;
+}
+
 @end /* EONotQualifier(IMAPAdditions) */
index b566891315796ceb142880c6a02dacd3888c900a..3995c095605740f2dc9b564e6eaeb9b9d11d60fa 100644 (file)
@@ -966,7 +966,7 @@ static BOOL         ImapDebugEnabled   = NO;
           qualifier:_qualifier];
     return nil;
   }
-  return result;
+  return [@" " stringByAppendingString:result];
 }
 
 - (NSDictionary *)threadBySubject:(BOOL)_bySubject
index 892cc325f1b5720eba090f05a05c4ee751aefb02..f1a8c404aa42e4f7b3986bf7ef5e506a3336a51a 100644 (file)
@@ -2,6 +2,6 @@
 
 MAJOR_VERSION:=4
 MINOR_VERSION:=5
-SUBMINOR_VERSION:=212
+SUBMINOR_VERSION:=213
 
 # v4.2.149 requires libNGStreams v4.2.34