From 2ad5e680965ba09dce07c4e4658b2c03c3bfb70c Mon Sep 17 00:00:00 2001 From: helge Date: Sun, 30 Jan 2005 23:30:21 +0000 Subject: [PATCH] improved bodystructure support in envelope classes git-svn-id: http://svn.opengroupware.org/SOPE/trunk@535 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-mime/ChangeLog | 11 ++ sope-mime/NGImap4/ChangeLog | 11 ++ sope-mime/NGImap4/NGImap4Envelope.h | 4 +- sope-mime/NGImap4/NGImap4Envelope.m | 53 ++++++++ sope-mime/NGImap4/NGImap4EnvelopeAddress.h | 5 +- sope-mime/NGImap4/NGImap4EnvelopeAddress.m | 11 ++ .../NGImap4/NGImap4Message+BodyStructure.h | 18 +-- sope-mime/NGImap4/NGImap4ResponseNormalizer.m | 123 +++++++++--------- sope-mime/NGImap4/NGImap4ResponseParser.m | 7 +- sope-mime/NGImap4/NGSieveClient.m | 2 +- sope-mime/Version | 2 +- 11 files changed, 174 insertions(+), 73 deletions(-) diff --git a/sope-mime/ChangeLog b/sope-mime/ChangeLog index c047e104..a86a3631 100644 --- a/sope-mime/ChangeLog +++ b/sope-mime/ChangeLog @@ -1,3 +1,14 @@ +2005-01-31 Helge Hess + + * NGImap4: added support for creating envelope objects from body + structure dictionaries (v4.5.209) + +2005-01-30 Helge Hess + + * NGImap4: code cleanup in response normalizer (v4.5.208) + + * NGImap4: some fix in the Sieve script upload (v4.5.207) + 2005-01-30 Helge Hess * v4.5.206 diff --git a/sope-mime/NGImap4/ChangeLog b/sope-mime/NGImap4/ChangeLog index 66b1316d..4f5e08b1 100644 --- a/sope-mime/NGImap4/ChangeLog +++ b/sope-mime/NGImap4/ChangeLog @@ -1,3 +1,14 @@ +2005-01-31 Helge Hess + + * NGImap4Envelope.m, NGImap4EnvelopeAddress.m: added support for + bodystructure dictionaries + +2005-01-30 Helge Hess + + * NGImap4ResponseNormalizer.m: code cleanup + + * NGSieveClient.m: removed a superflous "{" in the script-put call + 2005-01-30 Helge Hess * NGImap4Client.m: minor code cleanups diff --git a/sope-mime/NGImap4/NGImap4Envelope.h b/sope-mime/NGImap4/NGImap4Envelope.h index 9b787779..484f218f 100644 --- a/sope-mime/NGImap4/NGImap4Envelope.h +++ b/sope-mime/NGImap4/NGImap4Envelope.h @@ -30,7 +30,7 @@ Wraps the raw envelope as parsed from an IMAP4 fetch response. */ -@class NSString, NSArray, NSCalendarDate; +@class NSString, NSArray, NSCalendarDate, NSDictionary; @class NGImap4EnvelopeAddress; @interface NGImap4Envelope : NSObject @@ -52,6 +52,8 @@ sender:(id)_sender replyTo:(id)_replyTo to:(NSArray *)_to cc:(NSArray *)_cc bcc:(NSArray *)_bcc; +- (id)initWithBodyStructureInfo:(NSDictionary *)_info; + /* accessors */ - (NSCalendarDate *)date; diff --git a/sope-mime/NGImap4/NGImap4Envelope.m b/sope-mime/NGImap4/NGImap4Envelope.m index ef9ae6c8..d774dfe5 100644 --- a/sope-mime/NGImap4/NGImap4Envelope.m +++ b/sope-mime/NGImap4/NGImap4Envelope.m @@ -21,16 +21,31 @@ #include "NGImap4Envelope.h" #include "NGImap4EnvelopeAddress.h" +#include #include "imCommon.h" @implementation NGImap4Envelope +static NGMimeRFC822DateHeaderFieldParser *dateParser = nil; + ++ (void)initialize { + dateParser = [[NGMimeRFC822DateHeaderFieldParser alloc] init]; +} + - (id)newEnvelopeAddressForEMail:(id)_email { if (![_email isNotNull]) return nil; if ([_email isKindOfClass:[NGImap4EnvelopeAddress class]]) return [_email copy]; + + if ([_email isKindOfClass:[NSDictionary class]]) { + /* + A body structure dictionary, contains those keys: + hostName, mailboxName, personalName, sourceRoute + */ + return [[NGImap4EnvelopeAddress alloc] initWithBodyStructureInfo:_email]; + } _email = [_email stringValue]; if ([_email length] == 0) @@ -78,6 +93,44 @@ return self; } +- (id)initWithBodyStructureInfo:(NSDictionary *)_info { + id lFrom, lReplyTo, lDate; + + if (![_info isNotNull]) { + [self release]; + return nil; + } + + lFrom = [_info valueForKey:@"from"]; + lReplyTo = [_info valueForKey:@"reply-to"]; + + if ([lFrom isKindOfClass:[NSArray class]]) + lFrom = [lFrom count] > 0 ? [lFrom objectAtIndex:0] : nil; + if ([lReplyTo isKindOfClass:[NSArray class]]) + lReplyTo = [lReplyTo count] > 0 ? [lReplyTo objectAtIndex:0] : nil; + + self = [self initWithMessageID:[_info valueForKey:@"messageId"] + subject:[_info valueForKey:@"subject"] + sender:lFrom replyTo:lReplyTo + to:[_info valueForKey:@"to"] + cc:[_info valueForKey:@"cc"] + bcc:[_info valueForKey:@"bcc"]]; + if (self == nil) return nil; + + /* extended ivars */ + + self->inReplyTo = [[_info valueForKey:@"in-reply-to"] copy]; + + if ([(lDate = [_info valueForKey:@"date"]) isNotNull]) { + if ([lDate isKindOfClass:[NSDate class]]) + self->date = [lDate copy]; + else + self->date = [[dateParser parseValue:lDate ofHeaderField:@"date"] copy]; + } + + return self; +} + - (void)dealloc { [self->date release]; [self->subject release]; diff --git a/sope-mime/NGImap4/NGImap4EnvelopeAddress.h b/sope-mime/NGImap4/NGImap4EnvelopeAddress.h index 0a331ff3..28cb0d48 100644 --- a/sope-mime/NGImap4/NGImap4EnvelopeAddress.h +++ b/sope-mime/NGImap4/NGImap4EnvelopeAddress.h @@ -31,7 +31,7 @@ response. */ -@class NSString; +@class NSString, NSDictionary; @interface NGImap4EnvelopeAddress : NSObject < NSCopying > { @@ -44,8 +44,11 @@ - (id)initWithPersonalName:(NSString *)_pname sourceRoute:(NSString *)_route mailbox:(NSString *)_mbox host:(NSString *)_host; + - (id)initWithString:(NSString *)_str; +- (id)initWithBodyStructureInfo:(NSDictionary *)_info; + /* accessors */ - (NSString *)personalName; diff --git a/sope-mime/NGImap4/NGImap4EnvelopeAddress.m b/sope-mime/NGImap4/NGImap4EnvelopeAddress.m index c1ac9a31..98d87a16 100644 --- a/sope-mime/NGImap4/NGImap4EnvelopeAddress.m +++ b/sope-mime/NGImap4/NGImap4EnvelopeAddress.m @@ -52,6 +52,17 @@ mailbox:_str host:nil]; } +- (id)initWithBodyStructureInfo:(NSDictionary *)_info { + if (![_info isNotNull]) { + [self release]; + return nil; + } + return [self initWithPersonalName:[_info valueForKey:@"personalName"] + sourceRoute:[_info valueForKey:@"sourceRoute"] + mailbox:[_info valueForKey:@"mailboxName"] + host:[_info valueForKey:@"hostName"]]; +} + - (void)dealloc { [self->personalName release]; [self->sourceRoute release]; diff --git a/sope-mime/NGImap4/NGImap4Message+BodyStructure.h b/sope-mime/NGImap4/NGImap4Message+BodyStructure.h index 288dd468..3fe0874a 100644 --- a/sope-mime/NGImap4/NGImap4Message+BodyStructure.h +++ b/sope-mime/NGImap4/NGImap4Message+BodyStructure.h @@ -84,19 +84,19 @@ static id _buildMessage(id self, NSURL *_baseUrl, NSDictionary *_dict) { map = [NGMutableHashMap hashMapWithCapacity:4]; - if ((value = [_dict objectForKey:@"subject"])) { + if ([(value = [_dict objectForKey:@"subject"]) isNotNull]) [map setObject:value forKey:Fields->subject]; - } - if ((value = [_dict objectForKey:@"messageId"])) { + + if ([(value = [_dict objectForKey:@"messageId"]) isNotNull]) [map setObject:value forKey:Fields->messageID]; - } - if ((value = [_dict objectForKey:@"in-reply-to"])) { + + if ([(value = [_dict objectForKey:@"in-reply-to"]) isNotNull]) [map setObject:value forKey:@"in-reply-to"]; - } - if ((value = [_dict objectForKey:Fields->contentLength])) { + + if ([(value = [_dict objectForKey:Fields->contentLength]) isNotNull]) [map setObject:value forKey:Fields->contentLength]; - } - if ((value = [_dict objectForKey:@"date"])) { + + if ([(value = [_dict objectForKey:@"date"]) isNotNull]) { NSCalendarDate *d; if ((d = [NSCalendarDate calendarDateWithRfc822DateString:value])) diff --git a/sope-mime/NGImap4/NGImap4ResponseNormalizer.m b/sope-mime/NGImap4/NGImap4ResponseNormalizer.m index 09a61b98..8863cac1 100644 --- a/sope-mime/NGImap4/NGImap4ResponseNormalizer.m +++ b/sope-mime/NGImap4/NGImap4ResponseNormalizer.m @@ -285,63 +285,7 @@ static int LogImapEnabled = -1; dictionary for each response to the 'fetch' key of the normalized response dictionary (as retrieved by 'normalizeResponse') */ -- (NSDictionary *)normalizeFetchResponse:(NGHashMap *)_map { - /* - Raw Sample (Courier): - C[0x8b4e754]: 27 uid fetch 635 (body) - S[0x8c8b4e4]: * 627 FETCH (UID 635 BODY - ("text" "plain" ("charset" "iso-8859-1" "format" "flowed") - NIL NIL "8bit" 2474 51)) - S[0x8c8b4e4]: * 627 FETCH (FLAGS (\Seen)) - S[0x8c8b4e4]: 27 OK FETCH completed. - - this results in two result records (one for UID and one for FLAGS) - TODO: should we coalesce? - - Raw Sample (Cyrus): - C[0x8c8ec64]: 14 uid fetch 20199 (body) - S[0x8da46a4]: * 93 FETCH (UID 20199 BODY - ((("TEXT" "PLAIN" ("CHARSET" "utf-8") NIL "signed data" "7BIT" 691 17) - ("APPLICATION" "PKCS7-SIGNATURE" ("NAME" "smime.p7s") NIL - "signature" "BASE64" 2936) "SIGNED") - ("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 146 4) - "MIXED")) - S[0x8da46a4]: 14 OK Completed - - UID key is mapped to 'uid' - - BODY key is mapped to a nested body structure - - MSN is added for the '93'? (TODO: make sure this is the case) - - Sample returns (not for the above code!): - { - // other message stuff - fetch = ( - { - header = < NSData containing the header >; - size = 3314; - uid = 20187; - msn = 72; - flags = ( answered, deleted, seen ); - }, - ... for each fetch message ... - ) - } - */ - NSMutableDictionary *result; - id obj; - NSEnumerator *enumerator; - NSMutableArray *fetchResponseRecords; - - // TODO: describe what the generic normalize does. - // Q: do we need to run this before the following section or can we - // call this method just before [result setObject:...] ? (I guess - // the latter, because 'result' is not accessed, but who knows - // about side effects in this JR cruft :-( ) - result = [self normalizeResponse:_map]; - - fetchResponseRecords = [[NSMutableArray alloc] initWithCapacity:512]; - - /* walk over each response tag which is keyed by 'fetch' in the hashmap */ - enumerator = [_map objectEnumeratorForKey:@"fetch"]; - while ((obj = [enumerator nextObject])) { +- (NSDictionary *)normalizeFetchResponsePart:(id)obj { // TODO: shouldn't we use a specific object instead of NSDict for that? NSDictionary *entry; NSEnumerator *keyEnum; @@ -361,7 +305,7 @@ static int LogImapEnabled = -1; // TODO: this should add some error handling wrt the count? // TODO: this could return multiple values for the same key?! => fix that - while ((key = [keyEnum nextObject]) && (count < 9)) { + while (((key = [keyEnum nextObject]) != nil) && (count < 9)) { unsigned klen; unichar c; @@ -440,7 +384,68 @@ static int LogImapEnabled = -1; ? [[DictClass alloc] initWithObjects:values forKeys:keys count:count] : nil; - if (entry == nil) + return entry; /* returns retained object! */ +} +- (NSDictionary *)normalizeFetchResponse:(NGHashMap *)_map { + /* + Raw Sample (Courier): + C[0x8b4e754]: 27 uid fetch 635 (body) + S[0x8c8b4e4]: * 627 FETCH (UID 635 BODY + ("text" "plain" ("charset" "iso-8859-1" "format" "flowed") + NIL NIL "8bit" 2474 51)) + S[0x8c8b4e4]: * 627 FETCH (FLAGS (\Seen)) + S[0x8c8b4e4]: 27 OK FETCH completed. + - this results in two result records (one for UID and one for FLAGS) + TODO: should we coalesce? + + Raw Sample (Cyrus): + C[0x8c8ec64]: 14 uid fetch 20199 (body) + S[0x8da46a4]: * 93 FETCH (UID 20199 BODY + ((("TEXT" "PLAIN" ("CHARSET" "utf-8") NIL "signed data" "7BIT" 691 17) + ("APPLICATION" "PKCS7-SIGNATURE" ("NAME" "smime.p7s") NIL + "signature" "BASE64" 2936) "SIGNED") + ("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 146 4) + "MIXED")) + S[0x8da46a4]: 14 OK Completed + - UID key is mapped to 'uid' + - BODY key is mapped to a nested body structure + - MSN is added for the '93'? (TODO: make sure this is the case) + + Sample returns (not for the above code!): + { + // other message stuff + fetch = ( + { + header = < NSData containing the header >; + size = 3314; + uid = 20187; + msn = 72; + flags = ( answered, deleted, seen ); + }, + ... for each fetch message ... + ) + } + */ + NSMutableDictionary *result; + id obj; + NSEnumerator *enumerator; + NSMutableArray *fetchResponseRecords; + + // TODO: describe what the generic normalize does. + // Q: do we need to run this before the following section or can we + // call this method just before [result setObject:...] ? (I guess + // the latter, because 'result' is not accessed, but who knows + // about side effects in this JR cruft :-( ) + result = [self normalizeResponse:_map]; + + fetchResponseRecords = [[NSMutableArray alloc] initWithCapacity:512]; + + /* walk over each response tag which is keyed by 'fetch' in the hashmap */ + enumerator = [_map objectEnumeratorForKey:@"fetch"]; + while ((obj = [enumerator nextObject]) != nil) { + NSDictionary *entry; + + if ((entry = [self normalizeFetchResponsePart:obj]) == nil) continue; [fetchResponseRecords addObject:entry]; diff --git a/sope-mime/NGImap4/NGImap4ResponseParser.m b/sope-mime/NGImap4/NGImap4ResponseParser.m index 7e1c1203..7fd988d7 100644 --- a/sope-mime/NGImap4/NGImap4ResponseParser.m +++ b/sope-mime/NGImap4/NGImap4ResponseParser.m @@ -1039,7 +1039,7 @@ static BOOL _parseThreadResponse(NGImap4ResponseParser *self, mailbox name hostname eg: - (NIL NIL "helge.hess" "opengroupware.org") + ("Helge Hess" NIL "helge.hess" "opengroupware.org") */ NGImap4EnvelopeAddress *address; NSString *pname, *route, *mailbox, *host; @@ -1080,6 +1080,11 @@ static BOOL _parseThreadResponse(NGImap4ResponseParser *self, } - (NSArray *)_parseEnvelopeAddressStructures { + /* + Parses an array of envelopes, most common: + ((NIL NIL "users-admin" "opengroupware.org")) + (just one envelope in the array) + */ NSMutableArray *ma; if (_la(self, 0) != '(') { diff --git a/sope-mime/NGImap4/NGSieveClient.m b/sope-mime/NGImap4/NGSieveClient.m index b3749604..1f4c673a 100644 --- a/sope-mime/NGImap4/NGSieveClient.m +++ b/sope-mime/NGImap4/NGSieveClient.m @@ -419,7 +419,7 @@ static BOOL debugImap4 = NO; s = @"PUTSCRIPT \""; s = [s stringByAppendingString:_name]; - s = [s stringByAppendingString:@"\" {"]; + s = [s stringByAppendingString:@"\" "]; s = [s stringByAppendingFormat:@"{%d+}\r\n%@", [_script length], _script]; s = [s stringByAppendingString:@"\r\n"]; map = [self processCommand:s]; diff --git a/sope-mime/Version b/sope-mime/Version index 74d1c71b..87dde2f4 100644 --- a/sope-mime/Version +++ b/sope-mime/Version @@ -2,6 +2,6 @@ MAJOR_VERSION:=4 MINOR_VERSION:=5 -SUBMINOR_VERSION:=206 +SUBMINOR_VERSION:=209 # v4.2.149 requires libNGStreams v4.2.34 -- 2.39.5