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
23 #import "NGMimeBodyGenerator.h"
24 #import "NGMimePartGenerator.h"
25 #import "NGMimeMultipartBody.h"
26 #import "NGMimeJoinedData.h"
27 #import "NGMimeFileData.h"
31 @implementation NGMimeBodyGenerator
37 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
38 additionalHeaders:(NGMutableHashMap *)_addHeaders
39 delegate:(id)_delegate
41 return [self encodeData:[_part body]
43 additionalHeaders:_addHeaders];
46 - (NSData *)encodeData:(NSData *)_data
47 forPart:(id<NGMimePart>)_part
48 additionalHeaders:(NGMutableHashMap *)_addHeaders
54 return self->useMimeData;
57 - (void)setUseMimeData:(BOOL)_b {
58 self->useMimeData = _b;
61 @end /* NGMimeBodyGenerator */
63 @implementation NGMimeTextBodyGenerator
69 NSAssert2([super version] == 2,
70 @"invalid superclass (%@) version %i !",
71 NSStringFromClass([self superclass]), [super version]);
74 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
75 additionalHeaders:(NGMutableHashMap *)_addHeaders
76 delegate:(id)_delegate
78 NSStringEncoding encoding = [NSString defaultCStringEncoding];
84 if ([body isKindOfClass:[NSString class]]) {
85 data = [body dataUsingEncoding:encoding];
91 NSLog(@"WARNING: textBodyGenerator expect that body is"
92 @" kind of class NSString");
96 NSLog(@"WARNING(%s): generate empty body", __PRETTY_FUNCTION__);
99 return [self encodeData:data forPart:_part additionalHeaders:_addHeaders];
102 @end /* NGMimeTextBodyGenerator */
104 @implementation NGMimeRfc822BodyGenerator
110 NSAssert2([super version] == 2,
111 @"invalid superclass (%@) version %i !",
112 NSStringFromClass([self superclass]), [super version]);
115 - (id<NGMimePartGenerator>)generatorForPart:(id<NGMimePart>)_part {
118 g = [[[NGMimePartGenerator allocWithZone:[self zone]] init]
120 [g setUseMimeData:self->useMimeData];
124 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
125 additionalHeaders:(NGMutableHashMap *)_addHeaders
126 delegate:(id)_delegate
129 NGMimePartGenerator *gen = nil;
131 gen = (NGMimePartGenerator *)[self generatorForPart:_part];
132 [gen setDelegate:_delegate];
133 data = [gen generateMimeFromPart:[_part body]];
137 @end /* NGMimeRfc822BodyGenerator */
140 @implementation NGMimeMultipartBodyGenerator
142 static Class NGMimeFileDataClass = Nil;
143 static Class NGMimeJoinedDataClass = Nil;
149 NSAssert2([super version] == 2,
150 @"invalid superclass (%@) version %i !",
151 NSStringFromClass([self superclass]), [super version]);
153 NGMimeFileDataClass = [NGMimeFileData class];
154 NGMimeJoinedDataClass = [NGMimeJoinedData class];
157 + (NSString *)boundaryPrefix {
158 static NSString *BoundaryPrefix = nil;
160 if (BoundaryPrefix == nil) {
161 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
163 [[ud stringForKey:@"NGMime_MultipartBoundaryPrefix"] copy];
164 if (BoundaryPrefix == nil)
165 BoundaryPrefix = @"--=_=-_OpenGroupware_org_NGMime";
167 return BoundaryPrefix;
170 static inline BOOL _isBoundaryInArray(NGMimeMultipartBodyGenerator *self,
174 const unsigned char *boundary;
176 NSEnumerator *enumerator;
180 boundary = [_boundary cString];
181 length = [_boundary length];
182 enumerator = [_data objectEnumerator];
186 while ((data = [enumerator nextObject])) {
187 const unsigned char *bytes;
188 unsigned int dataLen;
191 if ([data isKindOfClass:NGMimeFileDataClass] ||
192 [data isKindOfClass:NGMimeJoinedDataClass])
195 bytes = [data bytes];
196 dataLen = [data length];
199 if (dataLen < length)
202 while ((cnt < dataLen) && ((dataLen - cnt) >= length)) {
203 if (bytes[cnt + 2] != '-') { // can`t be a boundary
208 if (bytes[cnt] == '\n') {// LF*-
209 if (bytes[cnt + 1] == '-') { // LF--
210 if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
216 else if (bytes[cnt] == '\r') { //CR*-
217 if (bytes[cnt + 1] == '-') { //CR--
218 if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
223 else if ((bytes[cnt + 1] == '\n') && (bytes[cnt + 3] == '-')) {
224 if (strncmp(boundary, bytes + cnt + 4, length) == 0) { // CRLF--
236 - (NSString *)buildBoundaryForPart:(id<NGMimePart>)_part data:(NSArray *)_data
237 additionalHeaders:(NGMutableHashMap *)_addHeaders
239 static int BoundaryUniqueCount = 0;
240 NSString *boundary = nil;
244 if ((boundary = [[_part contentType] valueOfParameter:@"boundary"]))
247 #if defined(__WIN32__)
248 pid = GetCurrentProcessId();
253 boundary = [NSString stringWithFormat:
254 @"--%@-%d-%f-%d------",
255 [NGMimeMultipartBodyGenerator boundaryPrefix],
256 pid, [[NSDate date] timeIntervalSince1970],
257 BoundaryUniqueCount++];
259 isUnique = _isBoundaryInArray(self, boundary, _data) ? NO : YES;
261 boundary = [NSString stringWithFormat:
262 @"--%@-%d-%f-%d-----",
263 [NGMimeMultipartBodyGenerator boundaryPrefix],
264 pid, [[NSDate date] timeIntervalSince1970],
265 BoundaryUniqueCount++];
267 { // setting content-type with boundary
268 NGMimeType *type = nil;
270 type = [_part contentType];
275 d = [[NSDictionary alloc] initWithObjectsAndKeys:
276 boundary, @"boundary", nil];
277 type = [NGMimeType mimeType:@"multipart" subType:@"mixed"
282 NSMutableDictionary *dict = nil;
284 dict = [NSMutableDictionary dictionaryWithDictionary:
285 [type parametersAsDictionary]];
286 [dict setObject:boundary forKey:@"boundary"];
287 type = [NGMimeType mimeType:[type type] subType:[type subType]
290 [_addHeaders setObject:type forKey:@"content-type"];
295 - (NSData *)buildDataWithBoundary:(NSString *)_boundary
296 partsData:(NSArray *)_parts
298 NSEnumerator *enumerator;
302 data = (self->useMimeData)
303 ? [[[NGMimeJoinedData alloc] init] autorelease]
304 : [NSMutableData dataWithCapacity:4096];
306 enumerator = [_parts objectEnumerator];
307 while ((part = [enumerator nextObject])) {
308 [data appendBytes:"--" length:2];
309 [data appendBytes:[_boundary cString] length:[_boundary length]];
310 [data appendBytes:"\n" length:1];
311 [data appendData:part];
312 [data appendBytes:"\n" length:1];
314 [data appendBytes:"--" length:2];
315 [data appendBytes:[_boundary cString] length:[_boundary length]];
316 [data appendBytes:"--\n" length:3];
320 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
321 additionalHeaders:(NGMutableHashMap *)_addHeaders
322 delegate:(id)_delegate
325 NGMimeMultipartBody *body = nil;
326 NSMutableData *data = nil;
328 NSArray *parts = nil;
329 id<NGMimePart> part = nil;
330 NSEnumerator *enumerator = nil;
331 NSString *boundary = nil;
332 NSMutableArray *partsData = nil;
333 NSAutoreleasePool *pool;
338 return [NSData data];
340 pool = [[NSAutoreleasePool alloc] init];
342 NSAssert1([body isKindOfClass:[NGMimeMultipartBody class]],
343 @"NGMimeMultipartBodyGenerator expect a NGMimeMultipartBody "
344 @"as body of part\n part: %@\n", _part);
346 data = (self->useMimeData)
347 ? [[[NGMimeJoinedData alloc] init] autorelease]
348 : [NSMutableData dataWithCapacity:4096];
350 if ([_delegate respondsToSelector:
351 @selector(multipartBodyGenerator:prefixForPart:)])
352 tmp = [_delegate multipartBodyGenerator:self prefixForPart:_part];
354 tmp = [self multipartBodyGenerator:self prefixForPart:_part
357 NSAssert([tmp isKindOfClass:[NSString class]],
358 @"prefix should be a NSString");
359 [data appendBytes:[tmp cString] length:[tmp length]];
362 parts = [body parts];
363 enumerator = [parts objectEnumerator];
364 partsData = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:4];
366 while ((part = [enumerator nextObject])) {
367 id<NGMimePartGenerator> gen = nil;
369 if ([_delegate respondsToSelector:
370 @selector(multipartBodyGenerator:generatorForPart:)]) {
371 gen = [_delegate multipartBodyGenerator:self generatorForPart:part];
374 gen = [self multipartBodyGenerator:self generatorForPart:part];
375 [gen setDelegate:_delegate];
376 [(id)gen setUseMimeData:self->useMimeData];
379 NSLog(@"WARNING(%s): got no generator", __PRETTY_FUNCTION__);
382 tmp = [gen generateMimeFromPart:part];
384 [partsData addObject:tmp];
387 boundary = [self buildBoundaryForPart:_part data:partsData
388 additionalHeaders:_addHeaders];
389 tmp = [self buildDataWithBoundary:boundary partsData:partsData];
392 [data appendData:tmp];
395 NSLog(@"WARNING(%s): couldn`t build multipart data", __PRETTY_FUNCTION__);
397 if ([_delegate respondsToSelector:
398 @selector(multipartBodyGenerator:suffixForPart:)])
399 tmp = [_delegate multipartBodyGenerator:self suffixForPart:_part];
401 tmp = [self multipartBodyGenerator:self suffixForPart:_part
404 NSAssert([tmp isKindOfClass:[NSString class]],
405 @"suffix should be a NSString");
406 [data appendBytes:[tmp cString] length:[tmp length]];
408 [partsData release]; partsData = nil;
411 return [data autorelease];
414 - (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
415 prefixForPart:(id<NGMimePart>)_part
416 mimeMultipart:(NGMimeMultipartBody *)_body {
418 return @""; // [_body prefix];
421 - (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
422 suffixForPart:(id<NGMimePart>)_part
423 mimeMultipart:(NGMimeMultipartBody *)_body {
425 return @""; //[_body suffix];
428 - (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
429 generatorForPart:(id<NGMimePart>)_part
433 gen = [[NGMimePartGenerator alloc] init];
434 [gen setUseMimeData:self->useMimeData];
435 return [gen autorelease];
438 @end /* NGMimeMultipartBodyGenerator */