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 #include "NGMimeBodyGenerator.h"
23 #include "NGMimePartGenerator.h"
24 #include "NGMimeMultipartBody.h"
25 #include "NGMimeJoinedData.h"
26 #include "NGMimeFileData.h"
31 @implementation NGMimeMultipartBodyGenerator
33 static Class NGMimeFileDataClass = Nil;
34 static Class NGMimeJoinedDataClass = Nil;
35 static BOOL debugOn = NO;
41 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
43 NSAssert2([super version] == 2,
44 @"invalid superclass (%@) version %i !",
45 NSStringFromClass([self superclass]), [super version]);
47 NGMimeFileDataClass = [NGMimeFileData class];
48 NGMimeJoinedDataClass = [NGMimeJoinedData class];
50 debugOn = [ud boolForKey:@"NGMimeGeneratorDebugEnabled"];
52 NSLog(@"WARNING[%@]: NGMimeGeneratorDebugEnabled is enabled!", self);
55 + (NSString *)boundaryPrefix {
56 static NSString *BoundaryPrefix = nil;
58 if (BoundaryPrefix == nil) {
59 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
61 [[ud stringForKey:@"NGMime_MultipartBoundaryPrefix"] copy];
62 if (BoundaryPrefix == nil)
63 BoundaryPrefix = @"--=_=-_OpenGroupware_org_NGMime";
65 return BoundaryPrefix;
68 static inline BOOL _isBoundaryInArray(NGMimeMultipartBodyGenerator *self,
72 const unsigned char *boundary;
74 NSEnumerator *enumerator;
78 // TODO: do we need to treat the boundary as a CString?
79 boundary = (const unsigned char *)[_boundary cString];
80 length = [_boundary length];
81 enumerator = [_data objectEnumerator];
85 while ((data = [enumerator nextObject]) != nil) {
86 const unsigned char *bytes;
90 if ([data isKindOfClass:NGMimeFileDataClass] ||
91 [data isKindOfClass:NGMimeJoinedDataClass])
95 dataLen = [data length];
101 while ((cnt < dataLen) && ((dataLen - cnt) >= length)) {
102 if (bytes[cnt + 2] != '-') { // can`t be a boundary
107 if (bytes[cnt] == '\n') {// LF*-
108 if (bytes[cnt + 1] == '-') { // LF--
109 if (strncmp((char *)boundary, (char *)(bytes+cnt+3), length) == 0) {
115 else if (bytes[cnt] == '\r') { //CR*-
116 if (bytes[cnt + 1] == '-') { //CR--
117 if (strncmp((char *)boundary, (char *)(bytes+cnt+3), length) == 0) {
122 else if ((bytes[cnt + 1] == '\n') && (bytes[cnt + 3] == '-')) {
123 if (strncmp((char*)boundary, (char *)(bytes+cnt+4), length)==0) { // CRLF--
135 - (NSString *)buildBoundaryForPart:(id<NGMimePart>)_part data:(NSArray *)_data
136 additionalHeaders:(NGMutableHashMap *)_addHeaders
138 static int BoundaryUniqueCount = 0;
139 NSString *boundary = nil;
143 if ((boundary = [[_part contentType] valueOfParameter:@"boundary"]))
146 #if defined(__WIN32__)
147 pid = GetCurrentProcessId();
152 boundary = [NSString stringWithFormat:
153 @"--%@-%d-%f-%d------",
154 [NGMimeMultipartBodyGenerator boundaryPrefix],
155 pid, [[NSDate date] timeIntervalSince1970],
156 BoundaryUniqueCount++];
158 isUnique = _isBoundaryInArray(self, boundary, _data) ? NO : YES;
160 boundary = [NSString stringWithFormat:
161 @"--%@-%d-%f-%d-----",
162 [NGMimeMultipartBodyGenerator boundaryPrefix],
163 pid, [[NSDate date] timeIntervalSince1970],
164 BoundaryUniqueCount++];
167 { // setting content-type with boundary
168 NGMimeType *type = nil;
170 type = [_part contentType];
175 d = [[NSDictionary alloc] initWithObjectsAndKeys:
176 boundary, @"boundary", nil];
177 type = [NGMimeType mimeType:@"multipart" subType:@"mixed"
182 NSMutableDictionary *dict = nil;
184 dict = [NSMutableDictionary dictionaryWithDictionary:
185 [type parametersAsDictionary]];
186 [dict setObject:boundary forKey:@"boundary"];
187 type = [NGMimeType mimeType:[type type] subType:[type subType]
190 [_addHeaders setObject:type forKey:@"content-type"];
195 - (NSData *)buildDataWithBoundary:(NSString *)_boundary
196 partsData:(NSArray *)_parts
198 NSEnumerator *enumerator;
202 data = (self->useMimeData)
203 ? [[[NGMimeJoinedData alloc] init] autorelease]
204 : [NSMutableData dataWithCapacity:4096];
206 enumerator = [_parts objectEnumerator];
207 while ((part = [enumerator nextObject])) {
208 [data appendBytes:"--" length:2];
209 [data appendBytes:[_boundary cString] length:[_boundary length]];
210 [data appendBytes:"\r\n" length:2];
211 [data appendData:part];
212 [data appendBytes:"\r\n" length:2];
214 [data appendBytes:"--" length:2];
215 [data appendBytes:[_boundary cString] length:[_boundary length]];
216 [data appendBytes:"--\r\n" length:4];
220 - (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
221 additionalHeaders:(NGMutableHashMap *)_addHeaders
222 delegate:(id)_delegate
225 NGMimeMultipartBody *body = nil;
226 NSMutableData *data = nil;
228 NSArray *parts = nil;
229 id<NGMimePart> part = nil;
230 NSEnumerator *enumerator = nil;
231 NSString *boundary = nil;
232 NSMutableArray *partsData = nil;
233 NSAutoreleasePool *pool;
238 return [NSData data];
240 pool = [[NSAutoreleasePool alloc] init];
242 NSAssert1([body isKindOfClass:[NGMimeMultipartBody class]],
243 @"NGMimeMultipartBodyGenerator expect a NGMimeMultipartBody "
244 @"as body of part\n part: %@\n", _part);
246 data = (self->useMimeData)
247 ? [[[NGMimeJoinedData alloc] init] autorelease]
248 : [NSMutableData dataWithCapacity:4096];
250 if ([_delegate respondsToSelector:
251 @selector(multipartBodyGenerator:prefixForPart:)])
252 tmp = [_delegate multipartBodyGenerator:self prefixForPart:_part];
254 tmp = [self multipartBodyGenerator:self prefixForPart:_part
257 NSAssert([tmp isKindOfClass:[NSString class]],
258 @"prefix should be a NSString");
259 [data appendBytes:[tmp cString] length:[tmp length]];
262 parts = [body parts];
263 enumerator = [parts objectEnumerator];
264 partsData = [[NSMutableArray alloc] initWithCapacity:4];
266 while ((part = [enumerator nextObject]) != nil) {
267 id<NGMimePartGenerator> gen = nil;
270 if ([_delegate respondsToSelector:
271 @selector(multipartBodyGenerator:generatorForPart:)]) {
272 gen = [_delegate multipartBodyGenerator:self generatorForPart:part];
275 gen = [self multipartBodyGenerator:self generatorForPart:part];
276 [gen setDelegate:_delegate];
277 [(id)gen setUseMimeData:self->useMimeData];
280 [self logWithFormat:@"WARNING(%s): got no generator",
281 __PRETTY_FUNCTION__];
287 data = [gen generateMimeFromPart:part];
290 [self debugWithFormat:
291 @"multipart body generated %d bytes using %@ for part: %@",
292 [data length], gen, part];
294 [partsData addObject:data];
297 [self debugWithFormat:
298 @"multipart body %@ did not generate content for part: %@",
302 boundary = [self buildBoundaryForPart:_part data:partsData
303 additionalHeaders:_addHeaders];
304 tmp = [self buildDataWithBoundary:boundary partsData:partsData];
307 [data appendData:tmp];
310 NSLog(@"WARNING(%s): couldn`t build multipart data", __PRETTY_FUNCTION__);
312 if ([_delegate respondsToSelector:
313 @selector(multipartBodyGenerator:suffixForPart:)])
314 tmp = [_delegate multipartBodyGenerator:self suffixForPart:_part];
316 tmp = [self multipartBodyGenerator:self suffixForPart:_part
319 NSAssert([tmp isKindOfClass:[NSString class]],
320 @"suffix should be a NSString");
321 [data appendBytes:[tmp cString] length:[tmp length]];
323 [partsData release]; partsData = nil;
326 return [data autorelease];
329 - (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
330 prefixForPart:(id<NGMimePart>)_part
331 mimeMultipart:(NGMimeMultipartBody *)_body
333 return @""; // [_body prefix];
336 - (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
337 suffixForPart:(id<NGMimePart>)_part
338 mimeMultipart:(NGMimeMultipartBody *)_body
340 return @""; //[_body suffix];
343 - (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
344 generatorForPart:(id<NGMimePart>)_part
348 gen = [[NGMimePartGenerator alloc] init];
349 [gen setUseMimeData:self->useMimeData];
350 return [gen autorelease];
355 - (BOOL)isDebuggingEnabled {
359 @end /* NGMimeMultipartBodyGenerator */