2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #import "NGMimeBodyGenerator.h"
23 #import "NGMimePartGenerator.h"
24 #import "NGMimeMultipartBody.h"
25 #import "NGMimeJoinedData.h"
26 #import "NGMimeFileData.h"
30 @implementation NGMimeBodyGenerator
36 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
37 additionalHeaders:(NGMutableHashMap *)_addHeaders
38 delegate:(id)_delegate
40 return [self encodeData:[_part body]
42 additionalHeaders:_addHeaders];
45 - (NSData *)encodeData:(NSData *)_data
46 forPart:(id<NGMimePart>)_part
47 additionalHeaders:(NGMutableHashMap *)_addHeaders
53 return self->useMimeData;
56 - (void)setUseMimeData:(BOOL)_b {
57 self->useMimeData = _b;
60 @end /* NGMimeBodyGenerator */
62 @implementation NGMimeTextBodyGenerator
68 NSAssert2([super version] == 2,
69 @"invalid superclass (%@) version %i !",
70 NSStringFromClass([self superclass]), [super version]);
73 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
74 additionalHeaders:(NGMutableHashMap *)_addHeaders
75 delegate:(id)_delegate
77 NSStringEncoding encoding = [NSString defaultCStringEncoding];
83 if ([body isKindOfClass:[NSString class]]) {
84 data = [body dataUsingEncoding:encoding];
90 NSLog(@"WARNING: textBodyGenerator expect that body is"
91 @" kind of class NSString");
95 NSLog(@"WARNING(%s): generate empty body", __PRETTY_FUNCTION__);
98 return [self encodeData:data forPart:_part additionalHeaders:_addHeaders];
101 @end /* NGMimeTextBodyGenerator */
103 @implementation NGMimeRfc822BodyGenerator
109 NSAssert2([super version] == 2,
110 @"invalid superclass (%@) version %i !",
111 NSStringFromClass([self superclass]), [super version]);
114 - (id<NGMimePartGenerator>)generatorForPart:(id<NGMimePart>)_part {
117 g = [[[NGMimePartGenerator allocWithZone:[self zone]] init]
119 [g setUseMimeData:self->useMimeData];
123 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
124 additionalHeaders:(NGMutableHashMap *)_addHeaders
125 delegate:(id)_delegate
128 NGMimePartGenerator *gen = nil;
130 gen = (NGMimePartGenerator *)[self generatorForPart:_part];
131 [gen setDelegate:_delegate];
132 data = [gen generateMimeFromPart:[_part body]];
136 @end /* NGMimeRfc822BodyGenerator */
139 @implementation NGMimeMultipartBodyGenerator
141 static Class NGMimeFileDataClass = Nil;
142 static Class NGMimeJoinedDataClass = Nil;
148 NSAssert2([super version] == 2,
149 @"invalid superclass (%@) version %i !",
150 NSStringFromClass([self superclass]), [super version]);
152 NGMimeFileDataClass = [NGMimeFileData class];
153 NGMimeJoinedDataClass = [NGMimeJoinedData class];
156 + (NSString *)boundaryPrefix {
157 static NSString *BoundaryPrefix = nil;
159 if (BoundaryPrefix == nil) {
160 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
162 [[ud stringForKey:@"NGMime_MultipartBoundaryPrefix"] copy];
163 if (BoundaryPrefix == nil)
164 BoundaryPrefix = @"--=_=-_OpenGroupware_org_NGMime";
166 return BoundaryPrefix;
169 static inline BOOL _isBoundaryInArray(NGMimeMultipartBodyGenerator *self,
173 const unsigned char *boundary;
175 NSEnumerator *enumerator;
179 boundary = [_boundary cString];
180 length = [_boundary length];
181 enumerator = [_data objectEnumerator];
185 while ((data = [enumerator nextObject])) {
186 const unsigned char *bytes;
187 unsigned int dataLen;
190 if ([data isKindOfClass:NGMimeFileDataClass] ||
191 [data isKindOfClass:NGMimeJoinedDataClass])
194 bytes = [data bytes];
195 dataLen = [data length];
198 if (dataLen < length)
201 while ((cnt < dataLen) && ((dataLen - cnt) >= length)) {
202 if (bytes[cnt + 2] != '-') { // can`t be a boundary
207 if (bytes[cnt] == '\n') {// LF*-
208 if (bytes[cnt + 1] == '-') { // LF--
209 if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
215 else if (bytes[cnt] == '\r') { //CR*-
216 if (bytes[cnt + 1] == '-') { //CR--
217 if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
222 else if ((bytes[cnt + 1] == '\n') && (bytes[cnt + 3] == '-')) {
223 if (strncmp(boundary, bytes + cnt + 4, length) == 0) { // CRLF--
235 - (NSString *)buildBoundaryForPart:(id<NGMimePart>)_part data:(NSArray *)_data
236 additionalHeaders:(NGMutableHashMap *)_addHeaders
238 static int BoundaryUniqueCount = 0;
239 NSString *boundary = nil;
243 if ((boundary = [[_part contentType] valueOfParameter:@"boundary"]))
246 #if defined(__WIN32__)
247 pid = GetCurrentProcessId();
252 boundary = [NSString stringWithFormat:
253 @"--%@-%d-%f-%d------",
254 [NGMimeMultipartBodyGenerator boundaryPrefix],
255 pid, [[NSDate date] timeIntervalSince1970],
256 BoundaryUniqueCount++];
258 isUnique = _isBoundaryInArray(self, boundary, _data) ? NO : YES;
260 boundary = [NSString stringWithFormat:
261 @"--%@-%d-%f-%d-----",
262 [NGMimeMultipartBodyGenerator boundaryPrefix],
263 pid, [[NSDate date] timeIntervalSince1970],
264 BoundaryUniqueCount++];
266 { // setting content-type with boundary
267 NGMimeType *type = nil;
269 type = [_part contentType];
274 d = [[NSDictionary alloc] initWithObjectsAndKeys:
275 boundary, @"boundary", nil];
276 type = [NGMimeType mimeType:@"multipart" subType:@"mixed"
281 NSMutableDictionary *dict = nil;
283 dict = [NSMutableDictionary dictionaryWithDictionary:
284 [type parametersAsDictionary]];
285 [dict setObject:boundary forKey:@"boundary"];
286 type = [NGMimeType mimeType:[type type] subType:[type subType]
289 [_addHeaders setObject:type forKey:@"content-type"];
294 - (NSData *)buildDataWithBoundary:(NSString *)_boundary
295 partsData:(NSArray *)_parts
297 NSEnumerator *enumerator;
301 data = (self->useMimeData)
302 ? [[[NGMimeJoinedData alloc] init] autorelease]
303 : [NSMutableData dataWithCapacity:4096];
305 enumerator = [_parts objectEnumerator];
306 while ((part = [enumerator nextObject])) {
307 [data appendBytes:"--" length:2];
308 [data appendBytes:[_boundary cString] length:[_boundary length]];
309 [data appendBytes:"\n" length:1];
310 [data appendData:part];
311 [data appendBytes:"\n" length:1];
313 [data appendBytes:"--" length:2];
314 [data appendBytes:[_boundary cString] length:[_boundary length]];
315 [data appendBytes:"--\n" length:3];
319 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
320 additionalHeaders:(NGMutableHashMap *)_addHeaders
321 delegate:(id)_delegate
324 NGMimeMultipartBody *body = nil;
325 NSMutableData *data = nil;
327 NSArray *parts = nil;
328 id<NGMimePart> part = nil;
329 NSEnumerator *enumerator = nil;
330 NSString *boundary = nil;
331 NSMutableArray *partsData = nil;
332 NSAutoreleasePool *pool;
337 return [NSData data];
339 pool = [[NSAutoreleasePool alloc] init];
341 NSAssert1([body isKindOfClass:[NGMimeMultipartBody class]],
342 @"NGMimeMultipartBodyGenerator expect a NGMimeMultipartBody "
343 @"as body of part\n part: %@\n", _part);
345 data = (self->useMimeData)
346 ? [[[NGMimeJoinedData alloc] init] autorelease]
347 : [NSMutableData dataWithCapacity:4096];
349 if ([_delegate respondsToSelector:
350 @selector(multipartBodyGenerator:prefixForPart:)])
351 tmp = [_delegate multipartBodyGenerator:self prefixForPart:_part];
353 tmp = [self multipartBodyGenerator:self prefixForPart:_part
356 NSAssert([tmp isKindOfClass:[NSString class]],
357 @"prefix should be a NSString");
358 [data appendBytes:[tmp cString] length:[tmp length]];
361 parts = [body parts];
362 enumerator = [parts objectEnumerator];
363 partsData = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:4];
365 while ((part = [enumerator nextObject])) {
366 id<NGMimePartGenerator> gen = nil;
368 if ([_delegate respondsToSelector:
369 @selector(multipartBodyGenerator:generatorForPart:)]) {
370 gen = [_delegate multipartBodyGenerator:self generatorForPart:part];
373 gen = [self multipartBodyGenerator:self generatorForPart:part];
374 [gen setDelegate:_delegate];
375 [(id)gen setUseMimeData:self->useMimeData];
378 NSLog(@"WARNING(%s): got no generator", __PRETTY_FUNCTION__);
381 tmp = [gen generateMimeFromPart:part];
383 [partsData addObject:tmp];
386 boundary = [self buildBoundaryForPart:_part data:partsData
387 additionalHeaders:_addHeaders];
388 tmp = [self buildDataWithBoundary:boundary partsData:partsData];
391 [data appendData:tmp];
394 NSLog(@"WARNING(%s): couldn`t build multipart data", __PRETTY_FUNCTION__);
396 if ([_delegate respondsToSelector:
397 @selector(multipartBodyGenerator:suffixForPart:)])
398 tmp = [_delegate multipartBodyGenerator:self suffixForPart:_part];
400 tmp = [self multipartBodyGenerator:self suffixForPart:_part
403 NSAssert([tmp isKindOfClass:[NSString class]],
404 @"suffix should be a NSString");
405 [data appendBytes:[tmp cString] length:[tmp length]];
407 [partsData release]; partsData = nil;
410 return [data autorelease];
413 - (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
414 prefixForPart:(id<NGMimePart>)_part
415 mimeMultipart:(NGMimeMultipartBody *)_body {
417 return @""; // [_body prefix];
420 - (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
421 suffixForPart:(id<NGMimePart>)_part
422 mimeMultipart:(NGMimeMultipartBody *)_body {
424 return @""; //[_body suffix];
427 - (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
428 generatorForPart:(id<NGMimePart>)_part
432 gen = [[NGMimePartGenerator alloc] init];
433 [gen setUseMimeData:self->useMimeData];
434 return [gen autorelease];
437 @end /* NGMimeMultipartBodyGenerator */