/* Copyright (C) 2000-2005 SKYRIX Software AG This file is part of SOPE. SOPE is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. SOPE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SOPE; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "NGMimePartGenerator.h" #include "NGMimeHeaderFieldGenerator.h" #include "NGMimeBodyGenerator.h" #include "NGMimeJoinedData.h" #include #include "common.h" @implementation NGMimePartGenerator + (int)version { return 2; } + (id)mimePartGenerator { return [[[self alloc] init] autorelease]; } - (void)dealloc { [self->result release]; [self->part release]; [super dealloc]; } /* setting the delegate */ - (void)setDelegate:(id)_delegate { self->delegate = _delegate; self->delegateRespondsTo.generatorGenerateDataForHeaderField = [self->delegate respondsToSelector: @selector(mimePartGenerator:generateDataForHeaderField:value:)]; self->delegateRespondsTo.generatorGeneratorForBodyOfPart = [self->delegate respondsToSelector: @selector(mimePartGenerator:generatorForBodyOfPart:)]; self->delegateRespondsTo.generatorGenerateDataForBodyOfPart = [self->delegate respondsToSelector: @selector(mimePartGenerator:generateDataForBodyOfPart: additionalHeaders:)]; } - (id)delegate { return self->delegate; } - (BOOL)prepareForGenerationOfPart:(id)_part { { id tmp = self->part; self->part = _part; [self->part retain]; [tmp release]; tmp = nil; } if (self->result) { [self->result release]; self->result = nil; } self->result = (self->useMimeData) ? [[NGMimeJoinedData alloc] init] : [[NSMutableData alloc] initWithCapacity:4096]; if ([self->result respondsToSelector:@selector(methodForSelector:)]) self->appendBytes = (void(*)(id,SEL,const void *, unsigned)) [self->result methodForSelector: @selector(appendBytes:length:)]; else self->appendBytes = NULL; return YES; } - (BOOL)generatePrefix { return YES; } - (void)generateSuffix { } - (id)generatorForHeaderField:(NSString *)_name { return [NGMimeHeaderFieldGeneratorSet defaultRfc822HeaderFieldGeneratorSet]; } - (NSData *)generateDataForHeaderField:(NSString *)_headerField value:(id)_value { NSData *data = nil; if (self->delegateRespondsTo.generatorGenerateDataForHeaderField) data = [self->delegate mimePartGenerator:self generateDataForHeaderField:_headerField value:_value]; else { data = [[self generatorForHeaderField:_headerField] generateDataForHeaderFieldNamed:_headerField value:_value]; } return data; } - (NSData *)generateDataWithHeaderField:(NSString *)_headerField values:(NSEnumerator *)_values { NSMutableData *res = nil; NSData *data = nil; id value = nil; const char *bytes = NULL; unsigned len = 0; res = [NSMutableData dataWithCapacity:64]; bytes = [_headerField cString]; len = [_headerField length]; while (len > 0) { if (*bytes != ' ') break; bytes++; len--; } while ((value = [_values nextObject])) { data = [self generateDataForHeaderField:(NSString *)_headerField value:value]; [res appendBytes:bytes length:len]; [res appendBytes:": " length:2]; [res appendData:data]; [res appendBytes:"\r\n" length:2]; } return res; } - (NSData *)generateHeaderData:(NGHashMap *)_additionalHeaders { NSEnumerator *headerFieldNames = nil; NSString *headerFieldName = nil; NGMutableHashMap *addHeaders = nil; NSMutableData *data = nil; data = (self->useMimeData) ? [[[NGMimeJoinedData alloc] init] autorelease] : [NSMutableData dataWithCapacity:2048]; headerFieldNames = [self->part headerFieldNames]; addHeaders = [_additionalHeaders mutableCopy]; while ((headerFieldName = [headerFieldNames nextObject])) { NSData *headerFieldData = nil; NSEnumerator *enumerator = nil; BOOL reset; if ([[_additionalHeaders objectsForKey:headerFieldName] count] > 0) { enumerator = [addHeaders objectEnumeratorForKey:headerFieldName]; reset = YES; } else { reset = NO; enumerator = [self->part valuesOfHeaderFieldWithName:headerFieldName]; } headerFieldData = [self generateDataWithHeaderField:headerFieldName values:enumerator]; if (reset) [addHeaders removeAllObjectsForKey:headerFieldName]; if (headerFieldData) [data appendData:headerFieldData]; } headerFieldNames = [addHeaders keyEnumerator]; while ((headerFieldName = [headerFieldNames nextObject])) { NSData *headerFieldData = nil; headerFieldData = [self generateDataWithHeaderField:headerFieldName values:[addHeaders objectEnumeratorForKey: headerFieldName]]; if (headerFieldData) [data appendData:headerFieldData]; } [addHeaders release]; addHeaders = nil; return data; } - (NGMimeType *)defaultContentTypeForPart:(id)_part { return [NGMimeType mimeType:@"application/octet"]; } - (id)defaultBodyGenerator { id gen; gen = [[[NGMimeBodyGenerator alloc] init] autorelease]; [(id)gen setUseMimeData:self->useMimeData]; return gen; } - (id)generatorForBodyOfPart:(id)_part { id bodyGen = nil; NGMimeType *contentType = nil; NSString *type = nil; if (self->delegateRespondsTo.generatorGeneratorForBodyOfPart) bodyGen = [self->delegate mimePartGenerator:self generatorForBodyOfPart:self->part]; if (!bodyGen) { contentType = [_part contentType]; if (contentType == nil) { contentType = [self defaultContentTypeForPart:_part]; } if (contentType == nil) { NSLog(@"WARNING(%s): no content-type", __PRETTY_FUNCTION__); return nil; } type = [contentType type]; if ([type isEqualToString:NGMimeTypeMultipart]) { bodyGen = [[[NGMimeMultipartBodyGenerator alloc] init] autorelease]; } else if ([type isEqualToString:NGMimeTypeText]) { bodyGen = [[[NGMimeTextBodyGenerator alloc] init] autorelease]; } else if (([type isEqualToString:NGMimeTypeMessage]) && [[contentType subType] isEqualToString:@"rfc822"]) { bodyGen = [[[NGMimeRfc822BodyGenerator alloc] init] autorelease]; } } [(id)bodyGen setUseMimeData:self->useMimeData]; return bodyGen; } - (NSData *)generateBodyData:(NGMutableHashMap *)_additionalHeaders { NSData *data = nil; id bodyGen = nil; if (self->delegateRespondsTo.generatorGenerateDataForBodyOfPart) { data = [self->delegate mimePartGenerator:self generateDataForBodyOfPart:self->part additionalHeaders:_additionalHeaders]; } else { bodyGen = [self generatorForBodyOfPart:self->part]; if (bodyGen == nil) // no generator for body bodyGen = [self defaultBodyGenerator]; [(id)bodyGen setUseMimeData:self->useMimeData]; if (bodyGen == nil) { id body = [self->part body]; NSLog(@"WARNING(%s): no defaultBodyGenerator", __PRETTY_FUNCTION__); if ([body isKindOfClass:[NSData class]]) { data = body; } else if ([body isKindOfClass:[NSString class]]) { data = [body dataUsingEncoding:[NSString defaultCStringEncoding]]; } } else { data = [bodyGen generateBodyOfPart:self->part additionalHeaders:_additionalHeaders delegate:self->delegate]; } } return data; } - (void)generateData { NGMutableHashMap *additionalHeaders = nil; NSData *bodyData = nil; NSData *headerData = nil; additionalHeaders = [[NGMutableHashMap alloc] initWithCapacity:16]; bodyData = [self generateBodyData:additionalHeaders]; headerData = [self generateHeaderData:additionalHeaders]; if (headerData != nil) { [self->result appendData:headerData]; [self->result appendBytes:"\r\n" length:2]; if (bodyData != nil) [self->result appendData:bodyData]; } [additionalHeaders release]; } - (NSData *)generateMimeFromPart:(id)_part { [self prepareForGenerationOfPart:_part]; if ([self generatePrefix]) { NSData *data; [self generateData]; [self generateSuffix]; data = self->result; self->result = nil; return [data autorelease]; } return nil; } - (NSString *)generateMimeFromPartToFile:(id)_part { NSString *filename = nil; static NSString *TmpPath = nil; static NSProcessInfo *Pi = nil; if (TmpPath == nil) { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; TmpPath = [ud stringForKey:@"NGMimeBuildMimeTempDirectory"]; if (TmpPath == nil) TmpPath = @"/tmp/"; TmpPath = [[TmpPath stringByAppendingPathComponent:@"OGo"] copy]; } if (Pi == nil) Pi = [[NSProcessInfo processInfo] retain]; filename = [Pi temporaryFileName:TmpPath]; [self setUseMimeData:YES]; if (![[self generateMimeFromPart:_part] writeToFile:filename atomically:YES]) { NSLog(@"ERROR[%s] couldn`t write data to temorary file %@", __PRETTY_FUNCTION__, filename); return nil; } return filename; } - (id)part { return self->part; } - (BOOL)useMimeData { return self->useMimeData; } - (void)setUseMimeData:(BOOL)_b { self->useMimeData = _b; } @end /* NGMimePartGenerator */