@implementation SOGoMailBodyPart
- (void)dealloc {
+ [self->partInfo release];
+ [self->identifier release];
+ [self->pathToPart release];
[super dealloc];
}
/* IMAP4 */
-- (NSString *)bodyPartIdentifier {
- NSMutableString *ms;
+- (NSString *)bodyPartName {
+ NSString *s;
+ NSRange r;
+
+ s = [self nameInContainer];
+ r = [s rangeOfString:@"."]; /* strip extensions */
+ if (r.length == 0)
+ return s;
+ return [s substringToIndex:r.location];
+}
+
+- (NSArray *)bodyPartPath {
+ NSMutableArray *p;
id obj;
- ms = [NSMutableString stringWithCapacity:16];
+ if (self->pathToPart != nil)
+ return [self->pathToPart isNotNull] ? self->pathToPart : nil;
+
+ p = [[NSMutableArray alloc] initWithCapacity:8];
for (obj = self; [obj isKindOfClass:[SOGoMailBodyPart class]];
obj = [obj container]) {
- NSString *s;
- NSRange r;
-
- s = [self nameInContainer];
- r = [s rangeOfString:@"."]; /* strip extensions */
- if (r.length > 0)
- s = [s substringToIndex:r.location];
-
- if ([ms length] > 0) {
- [ms insertString:@"." atIndex:0];
- [ms insertString:s atIndex:0];
- }
- else
- [ms appendString:s];
+ [p insertObject:[obj bodyPartName] atIndex:0];
}
- return ms;
+
+ self->pathToPart = [p copy];
+ [p release];
+ return self->pathToPart;
+}
+
+- (NSString *)bodyPartIdentifier {
+ if (self->identifier != nil)
+ return [self->identifier isNotNull] ? self->identifier : nil;
+
+ self->identifier =
+ [[[self bodyPartPath] componentsJoinedByString:@"."] copy];
+ return self->identifier;
}
- (NSURL *)imap4URL {
return [[self mailObject] imap4URL];
}
+/* part info */
+
+- (id)partInfo {
+ if (self->partInfo != nil)
+ return [self->partInfo isNotNull] ? self->partInfo : nil;
+
+ self->partInfo =
+ [[[self mailObject] lookupInfoForBodyPart:[self bodyPartPath]] retain];
+ return self->partInfo;
+}
+
/* name lookup */
- (id)lookupImap4BodyPartKey:(NSString *)_key inContext:(id)_ctx {
- (NSData *)fetchBLOB {
// HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, TEXT
- return [[self mailManager] fetchContentOfBodyPart:[self bodyPartIdentifier]
+ NSString *enc;
+ NSData *data;
+
+ data = [[self mailManager] fetchContentOfBodyPart:[self bodyPartIdentifier]
atURL:[self imap4URL]
password:[self imap4Password]];
+ if (data == nil) return nil;
+
+ /* check for content encodings */
+
+ if ((enc = [[self partInfo] valueForKey:@"encoding"]) != nil) {
+ enc = [enc uppercaseString];
+
+ if ([enc isEqualToString:@"BASE64"])
+ data = [data dataByDecodingBase64];
+ else if ([enc isEqualToString:@"7BIT"])
+ ; /* keep data as is */ // TODO: do we need to change encodings?
+ else
+ [self debugWithFormat:@"ERROR: unsupported encoding: %@", enc];
+ }
+
+ return data;
}
/* WebDAV */
+- (NSString *)contentTypeForBodyPartInfo:(id)_info {
+ NSString *mt, *st;
+
+ if (![_info isNotNull])
+ return nil;
+
+ mt = [_info valueForKey:@"type"]; if (![mt isNotNull]) return nil;
+ st = [_info valueForKey:@"subtype"]; if (![st isNotNull]) return nil;
+
+ // TODO: we could add the parameter list?!
+ return [[mt stringByAppendingString:@"/"] stringByAppendingString:st];
+}
+
- (NSString *)davContentType {
// TODO: what about the content-type and other headers?
// => we could pass them in as the extension? (eg generate 1.gif!)
NSString *pe;
+ /* try type from body structure info */
+
+ if ((pe = [self contentTypeForBodyPartInfo:[self partInfo]]) != nil)
+ return pe;
+
+ /* construct type */
+
pe = [[self nameInContainer] pathExtension];
if ([pe length] == 0)
return @"application/octet-stream";
return [NSException exceptionWithHTTPStatus:404 /* not found */
reason:@"did not find body part"];
}
-
- [self debugWithFormat:@" fetched %d bytes.", [data length]];
+ [self debugWithFormat:@" fetched %d bytes: %@", [data length],
+ [self partInfo]];
+
+ // TODO: wrong, could be encoded
r = [_ctx response];
[r setHeader:[self davContentType] forKey:@"content-type"];
[r setHeader:[NSString stringWithFormat:@"%d", [data length]]
return self->coreInfos;
}
+- (id)bodyStructure {
+ return [[self fetchCoreInfos] valueForKey:@"body"];
+}
+
- (NGImap4Envelope *)envelope {
return [[self fetchCoreInfos] valueForKey:@"envelope"];
}
return [[self envelope] cc];
}
+- (id)lookupInfoForBodyPart:(NSArray *)_path {
+ NSEnumerator *pe;
+ NSString *p;
+ id info;
+
+ info = [self bodyStructure];
+ pe = [_path objectEnumerator];
+ while ((p = [pe nextObject])) {
+ unsigned idx;
+ NSArray *parts;
+
+ idx = [p intValue] - 1;
+
+ parts = [info valueForKey:@"parts"];
+ if (idx >= [parts count]) {
+ [self logWithFormat:@"ERROR: body part index out of bounds: %d", idx+1];
+ return nil;
+ }
+ info = [parts objectAtIndex:idx];
+ }
+ return [info isNotNull] ? info : nil;
+}
+
/* name lookup */
- (BOOL)isBodyPartKey:(NSString *)_key inContext:(id)_ctx {