+2005-01-30 Helge Hess <helge.hess@skyrix.com>
+
+ * v4.5.206
+
+ * NGMail: fixed a crasher in a warn-log (occurred if no content-type
+ was set), major reorgs
+
+ * NGMime: some code cleanups, added MIME generation debugging,
+ improved NGMimeJoinedData, make reorgs
+
+ * NGImap4: minor code cleanups
+
2005-01-04 Helge Hess <helge.hess@opengroupware.org>
* NGImap4: fixed a small warning with Xcode (v4.5.205)
+2005-01-30 Helge Hess <helge.hess@skyrix.com>
+
+ * NGImap4Client.m: minor code cleanups
+
2005-01-04 Helge Hess <helge.hess@opengroupware.org>
* NGSieveClient.m: fixed a warning when compiling with Xcode
while (cntOld < (len - 1)) {
if (old[cntOld] == '\n') {
- new[cntNew++] = '\r';
- new[cntNew++] = '\n';
+ new[cntNew] = '\r'; cntNew++;
+ new[cntNew] = '\n'; cntNew++;
}
else if (old[cntOld] != '\r') {
- new[cntNew++] = old[cntOld];
+ new[cntNew] = old[cntOld]; cntNew++;
}
cntOld++;
}
if (old[cntOld] == '\n') {
- new[cntNew++] = '\r';
- new[cntNew++] = '\n';
+ new[cntNew] = '\r'; cntNew++;
+ new[cntNew] = '\n'; cntNew++;
}
else if (old[cntOld] != '\r') {
- new[cntNew++] = old[cntOld];
- }
- message = [(NSString *)[NSString alloc]
- initWithCString:new length:cntNew];
- if (new) free(new); new = NULL;
+ new[cntNew] = old[cntOld]; cntNew++;
+ }
+
+ // TODO: fix this junk, do not treat the message as a string, its NSData
+ message = [(NSString *)[NSString alloc] initWithCString:new length:cntNew];
+ if (new != NULL) free(new); new = NULL;
}
icmd = [NSString stringWithFormat:@"append \"%@\" (%@) {%d}",
result = [self processCommand:icmd
withTag:YES withNotification:NO];
+ // TODO: explain that
if ([[result objectForKey:@"ContinuationResponse"] boolValue])
result = [self processCommand:message withTag:NO];
return YES;
}
[self resetLastException];
-
+
dict = [[self->context client] select:[self absoluteName]];
if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__]) {
self->failedFlags.select = YES;
+2005-01-30 Helge Hess <helge.hess@opengroupware.org>
+
+ * NGMimeMessageGenerator.m: fixed a format bug in an error log which
+ could lead to a crash, moved base64 encoding function to separate
+ file
+
2004-12-14 Marcus Mueller <znek@mulle-kybernetik.com>
* NGMail.xcode: minor fixes and updated
NGMimeMessageMultipartBodyGenerator.m \
NGMimeMessageRfc822BodyGenerator.m \
NGMimeMessageTextBodyGenerator.m \
+ \
+ NGMailBase64Encoding.m \
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/subproject.make
--- /dev/null
+/*
+ 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 "NGMimeMessageGenerator.h"
+#include "NGMimeMessage.h"
+#include <NGMime/NGMimeFileData.h>
+#include "common.h"
+
+/* Defaults
+ Mail_Use_8bit_Encoding_For_Text[BOOL] --
+ Use 8bit content-transfer-encoding for
+ text messages
+*/
+
+NSData *
+_base64Encoding(NGMimeBodyGenerator *self,
+ NSData *_data_,
+ id<NGMimePart>_part,
+ NGMutableHashMap *_addHeaders)
+{
+ NSString *transEnc = nil;
+ const char *bytes = NULL;
+ unsigned length = 0;
+
+ /* kinda hack, treat NGMimeFileData objects as already encoded */
+
+ if ([_data_ isKindOfClass:[NGMimeFileData class]])
+ return _data_;
+
+ /* encoding */
+
+ bytes = [_data_ bytes];
+ length = [_data_ length];
+
+ while (length > 0) {
+ if ((unsigned char)*bytes > 127) {
+ break;
+ }
+ bytes++;
+ length--;
+ }
+ if (length > 0) { // should be encoded
+ NGMimeType *type;
+
+ type = [_part contentType];
+
+ if ([[type type] isEqualToString:@"text"]) {
+ NSUserDefaults *ud;
+ BOOL use8bit;
+
+ ud = [NSUserDefaults standardUserDefaults];
+ use8bit = [ud boolForKey:@"Mail_Use_8bit_Encoding_For_Text"];
+
+ if (use8bit)
+ transEnc = @"8bit";
+ else {
+ _data_ = [_data_ dataByEncodingQuotedPrintable];
+ transEnc = @"quoted-printable";
+ }
+ }
+ else {
+ NGMimeType *appOctet;
+
+ _data_ = [_data_ dataByEncodingBase64];
+ transEnc = @"base64";
+
+ appOctet = [NGMimeType mimeType:@"application" subType:@"octet-stream"];
+ if (type == nil)
+ [_addHeaders setObject:appOctet forKey:@"content-type"];
+ }
+ }
+ else /* no encoding */
+ transEnc = @"7bit";
+
+ [_addHeaders setObject:transEnc forKey:@"content-transfer-encoding"];
+ [_addHeaders setObject:[NSNumber numberWithInt:[_data_ length]]
+ forKey:@"content-length"];
+ return _data_;
+}
/* NGPart */
- (NSEnumerator *)valuesOfHeaderFieldWithName:(NSString *)_name {
- if ([_name isEqualToString:@"content-type"] == YES) {
+ if ([_name isEqualToString:@"content-type"])
return [[NSArray arrayWithObject:[self contentType]] objectEnumerator];
- }
+
return [self->header objectEnumeratorForKey:_name];
}
- (NSEnumerator *)headerFieldNames {
/* NGMimePart */
- (NGMimeType *)autodetectContentType {
- NGMimeType *type = nil;
+ const char *bytes;
+ unsigned length;
- if ((self->body != nil) &&
- ([self->body isKindOfClass:[NSData class]] == YES)) {
- const char *bytes = NULL;
- unsigned length = 0;
-
- bytes = [self->body bytes];
- length = [self->body length];
-
- while (length > 0) {
- if ((unsigned char)*bytes > 127) {
- break;
- }
- bytes++;
- length--;
- }
- type = (length > 0) ? defaultDataType : defaultTextType;
- }
- else
- type = defaultTextType;
+ if (!((self->body != nil) && [self->body isKindOfClass:[NSData class]]))
+ return defaultTextType;
- return type;
+ bytes = [self->body bytes];
+ length = [self->body length];
+ while (length > 0) {
+ if ((unsigned char)*bytes > 127)
+ break;
+
+ bytes++;
+ length--;
+ }
+ return (length > 0) ? defaultDataType : defaultTextType;
}
- (NGMimeType *)contentType {
NSStringFromClass([self superclass]), [super version]);
}
+/* encoding data */
+
- (NSData *)encodeData:(NSData *)_data
forPart:(id<NGMimePart>)_part
additionalHeaders:(NGMutableHashMap *)_addHeaders
#include <NGMime/NGMimeFileData.h>
#include "common.h"
-/* Defaults
- Mail_Use_8bit_Encoding_For_Text[BOOL] --
- Use 8bit content-transfer-encoding for
- text messages
-*/
-
-NSData *
-_base64Encoding(NGMimeBodyGenerator *self,
- NSData *_data_,
- id<NGMimePart>_part,
- NGMutableHashMap *_addHeaders)
-{
- NSString *transEnc = nil;
- const char *bytes = NULL;
- unsigned length = 0;
-
- if ([_data_ isKindOfClass:[NGMimeFileData class]])
- return _data_;
-
- bytes = [_data_ bytes];
- length = [_data_ length];
-
- while (length > 0) {
- if ((unsigned char)*bytes > 127) {
- break;
- }
- bytes++;
- length--;
- }
- if (length > 0) { // should be encoded
- NGMimeType *type;
-
- type = [_part contentType];
-
- if ([[type type] isEqualToString:@"text"] == YES) {
- NSUserDefaults *ud;
- BOOL use8bit;
-
- ud = [NSUserDefaults standardUserDefaults];
- use8bit = [ud boolForKey:@"Mail_Use_8bit_Encoding_For_Text"];
-
- if (use8bit)
- transEnc = @"8bit";
- else {
- _data_ = [_data_ dataByEncodingQuotedPrintable];
- transEnc = @"quoted-printable";
- }
- }
- else {
- NGMimeType *appOctet;
-
- _data_ = [_data_ dataByEncodingBase64];
- transEnc = @"base64";
-
- appOctet = [NGMimeType mimeType:@"application" subType:@"octet-stream"];
- if (type == nil)
- [_addHeaders setObject:appOctet forKey:@"content-type"];
- }
- }
- else /* no encoding */
- transEnc = @"7bit";
-
- [_addHeaders setObject:transEnc forKey:@"content-transfer-encoding"];
- [_addHeaders setObject:[NSNumber numberWithInt:[_data_ length]]
- forKey:@"content-length"];
- return _data_;
-}
-
@implementation NGMimeMessageGenerator
+static BOOL debugOn = NO;
+
+ (int)version {
return 2;
}
+ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
NSAssert2([super version] == 2,
@"invalid superclass (%@) version %i !",
NSStringFromClass([self superclass]), [super version]);
+
+ debugOn = [ud boolForKey:@"NGMimeGeneratorDebugEnabled"];
+ if (debugOn)
+ NSLog(@"WARNING[%@]: NGMimeGeneratorDebugEnabled is enabled!", self);
}
/* header field specifics */
}
- (id<NGMimeBodyGenerator>)generatorForBodyOfPart:(id<NGMimePart>)_part {
+ /* called by -generateBodyData:? */
id<NGMimeBodyGenerator> bodyGen;
NGMimeType *contentType;
NSString *type;
contentType = [self defaultContentTypeForPart:_part];
if (contentType == nil) {
- NSLog(@"WARNING(%s): missing content-type in part 0x%08X.", _part);
+ [self logWithFormat:@"WARNING(%s): missing content-type in part 0x%08X.",
+ __PRETTY_FUNCTION__, _part];
return nil;
}
[[contentType subType] isEqualToString:@"rfc822"]) {
generatorClass = [NGMimeMessageRfc822BodyGenerator class];
}
+
+ if (generatorClass == Nil) {
+ [self debugWithFormat:
+ @"found no body generator class for part with type: %@",
+ contentType];
+ return nil;
+ }
+
+ if (debugOn) {
+ [self debugWithFormat:@"using body generator class %@ for part: %@",
+ generatorClass, _part];
+ }
+
+ /* allocate generator */
bodyGen = [[[generatorClass alloc] init] autorelease];
[(id)bodyGen setUseMimeData:self->useMimeData];
return bodyGen;
}
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+ return debugOn;
+}
+
@end /* NGMimeMessageGenerator */
}
}
}
- if (appendLC == YES) {
+ if (appendLC) {
if (cnt < length) {
buffer[bufLen] = bytes[cnt];
bufLen++;
+2005-01-30 Helge Hess <helge.hess@opengroupware.org>
+
+ * NGMimeContentTypeHeaderFieldGenerator.m, NGPart.m: fixed default
+ type ("application/octet-stream", not "application/octet")
+
+ * NGMimePartGenerator.m: code cleanups, added support for
+ 'NGMimeGeneratorDebugEnabled' default, properly generate \r\n instead
+ of just \n as a header/body separator, add a hack to avoid duplicate
+ generation of the \r\n header/body separator (needs to get tested)
+
+ * NGMimeJoinedData.m: code cleanups, added a -length method
+
+ * NGMimeMultipartBodyGenerator.m: enable debug logs when
+ 'NGMimeGeneratorDebugEnabled' default is enabled
+
+ * NGMimeBodyGenerator.m: moved NGMimeMultipartBodyGenerator to own
+ file, added support for 'NGMimeGeneratorDebugEnabled' default
+
2004-12-14 Marcus Mueller <znek@mulle-kybernetik.com>
* NGMime.xcode: minor fixes and updated
NGMimeHeaderFieldGeneratorSet.m \
NGMimeRFC822DateHeaderFieldGenerator.m \
NGMimeStringHeaderFieldGenerator.m \
+ \
+ NGMimeMultipartBodyGenerator.m \
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/subproject.make
02111-1307, USA.
*/
-#import "NGMimeBodyGenerator.h"
-#import "NGMimePartGenerator.h"
-#import "NGMimeMultipartBody.h"
-#import "NGMimeJoinedData.h"
-#import "NGMimeFileData.h"
-#import "common.h"
-#include <unistd.h>
+#include "NGMimeBodyGenerator.h"
+#include "NGMimePartGenerator.h"
+#include "common.h"
@implementation NGMimeBodyGenerator
+static BOOL debugOn = NO;
+
+ (int)version {
return 2;
}
++ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+ debugOn = [ud boolForKey:@"NGMimeGeneratorDebugEnabled"];
+ if (debugOn)
+ NSLog(@"WARNING[%@]: NGMimeGeneratorDebugEnabled is enabled!", self);
+}
+
+/* generate data for body */
- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
additionalHeaders:(NGMutableHashMap *)_addHeaders
delegate:(id)_delegate
{
- return [self encodeData:[_part body]
- forPart:_part
- additionalHeaders:_addHeaders];
+ NSData *data, *input;
+
+ input = [_part body];
+ data = [self encodeData:input
+ forPart:_part
+ additionalHeaders:_addHeaders];
+ if (debugOn) {
+ [self debugWithFormat:@"encoded %d bytes to %d bytes (same=%s, class=%@)",
+ [input length], [data length],
+ input == data ? "yes" : "no",
+ NSStringFromClass([data class])];
+ }
+ return data;
}
+/* properly encode data for transfer (eg to 7bit for email) */
+
- (NSData *)encodeData:(NSData *)_data
forPart:(id<NGMimePart>)_part
additionalHeaders:(NGMutableHashMap *)_addHeaders
return _data;
}
+/* manage data storage */
+
+- (void)setUseMimeData:(BOOL)_b {
+ self->useMimeData = _b;
+}
- (BOOL)useMimeData {
return self->useMimeData;
}
-- (void)setUseMimeData:(BOOL)_b {
- self->useMimeData = _b;
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+ return debugOn;
}
@end /* NGMimeBodyGenerator */
+
@implementation NGMimeTextBodyGenerator
+ (int)version {
additionalHeaders:(NGMutableHashMap *)_addHeaders
delegate:(id)_delegate
{
- NSStringEncoding encoding = [NSString defaultCStringEncoding];
- NSData *data = nil;
- id body = nil;
+ NSStringEncoding encoding;
+ NSData *data;
+ id body;
+ encoding = [NSString defaultCStringEncoding];
body = [_part body];
-
+
if ([body isKindOfClass:[NSString class]]) {
+ // TODO: deal with charset in content-type!
data = [body dataUsingEncoding:encoding];
}
else
@end /* NGMimeTextBodyGenerator */
+
@implementation NGMimeRfc822BodyGenerator
+ (int)version {
- (id<NGMimePartGenerator>)generatorForPart:(id<NGMimePart>)_part {
id g;
-
- g = [[[NGMimePartGenerator allocWithZone:[self zone]] init]
- autorelease];
+
+ g = [[[NGMimePartGenerator alloc] init] autorelease];
[g setUseMimeData:self->useMimeData];
return g;
}
additionalHeaders:(NGMutableHashMap *)_addHeaders
delegate:(id)_delegate
{
- NSData *data = nil;
- NGMimePartGenerator *gen = nil;
+ NSData *data;
+ NGMimePartGenerator *gen;
gen = (NGMimePartGenerator *)[self generatorForPart:_part];
[gen setDelegate:_delegate];
}
@end /* NGMimeRfc822BodyGenerator */
-
-
-@implementation NGMimeMultipartBodyGenerator
-
-static Class NGMimeFileDataClass = Nil;
-static Class NGMimeJoinedDataClass = Nil;
-
-+ (int)version {
- return 2;
-}
-+ (void)initialize {
- NSAssert2([super version] == 2,
- @"invalid superclass (%@) version %i !",
- NSStringFromClass([self superclass]), [super version]);
-
- NGMimeFileDataClass = [NGMimeFileData class];
- NGMimeJoinedDataClass = [NGMimeJoinedData class];
-}
-
-+ (NSString *)boundaryPrefix {
- static NSString *BoundaryPrefix = nil;
-
- if (BoundaryPrefix == nil) {
- NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
- BoundaryPrefix =
- [[ud stringForKey:@"NGMime_MultipartBoundaryPrefix"] copy];
- if (BoundaryPrefix == nil)
- BoundaryPrefix = @"--=_=-_OpenGroupware_org_NGMime";
- }
- return BoundaryPrefix;
-}
-
-static inline BOOL _isBoundaryInArray(NGMimeMultipartBodyGenerator *self,
- NSString *_boundary,
- NSArray *_data)
-{
- const unsigned char *boundary;
- unsigned int length;
- NSEnumerator *enumerator;
- NSData *data;
- BOOL wasFound;
-
- boundary = [_boundary cString];
- length = [_boundary length];
- enumerator = [_data objectEnumerator];
- data = nil;
- wasFound = NO;
-
- while ((data = [enumerator nextObject])) {
- const unsigned char *bytes;
- unsigned int dataLen;
- unsigned cnt;
-
- if ([data isKindOfClass:NGMimeFileDataClass] ||
- [data isKindOfClass:NGMimeJoinedDataClass])
- continue;
-
- bytes = [data bytes];
- dataLen = [data length];
- cnt = 0;
-
- if (dataLen < length)
- return NO;
-
- while ((cnt < dataLen) && ((dataLen - cnt) >= length)) {
- if (bytes[cnt + 2] != '-') { // can`t be a boundary
- cnt++;
- continue;
- }
-
- if (bytes[cnt] == '\n') {// LF*-
- if (bytes[cnt + 1] == '-') { // LF--
- if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
- wasFound = YES;
- break;
- }
- }
- }
- else if (bytes[cnt] == '\r') { //CR*-
- if (bytes[cnt + 1] == '-') { //CR--
- if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
- wasFound = YES;
- break;
- }
- }
- else if ((bytes[cnt + 1] == '\n') && (bytes[cnt + 3] == '-')) {
- if (strncmp(boundary, bytes + cnt + 4, length) == 0) { // CRLF--
- wasFound = YES;
- break;
- }
- }
- }
- cnt++;
- }
- }
- return wasFound;
-}
-
-- (NSString *)buildBoundaryForPart:(id<NGMimePart>)_part data:(NSArray *)_data
- additionalHeaders:(NGMutableHashMap *)_addHeaders
-{
- static int BoundaryUniqueCount = 0;
- NSString *boundary = nil;
- BOOL isUnique = NO;
- unsigned pid;
-
- if ((boundary = [[_part contentType] valueOfParameter:@"boundary"]))
- return boundary;
-
-#if defined(__WIN32__)
- pid = GetCurrentProcessId();
-#else
- pid = getpid();
-#endif
-
- boundary = [NSString stringWithFormat:
- @"--%@-%d-%f-%d------",
- [NGMimeMultipartBodyGenerator boundaryPrefix],
- pid, [[NSDate date] timeIntervalSince1970],
- BoundaryUniqueCount++];
- while (!isUnique) {
- isUnique = _isBoundaryInArray(self, boundary, _data) ? NO : YES;
- if (!isUnique)
- boundary = [NSString stringWithFormat:
- @"--%@-%d-%f-%d-----",
- [NGMimeMultipartBodyGenerator boundaryPrefix],
- pid, [[NSDate date] timeIntervalSince1970],
- BoundaryUniqueCount++];
- }
- { // setting content-type with boundary
- NGMimeType *type = nil;
-
- type = [_part contentType];
-
- if (type == nil) {
- NSDictionary *d;
-
- d = [[NSDictionary alloc] initWithObjectsAndKeys:
- boundary, @"boundary", nil];
- type = [NGMimeType mimeType:@"multipart" subType:@"mixed"
- parameters:d];
- [d release];
- }
- else {
- NSMutableDictionary *dict = nil;
-
- dict = [NSMutableDictionary dictionaryWithDictionary:
- [type parametersAsDictionary]];
- [dict setObject:boundary forKey:@"boundary"];
- type = [NGMimeType mimeType:[type type] subType:[type subType]
- parameters:dict];
- }
- [_addHeaders setObject:type forKey:@"content-type"];
- }
- return boundary;
-}
-
-- (NSData *)buildDataWithBoundary:(NSString *)_boundary
- partsData:(NSArray *)_parts
-{
- NSEnumerator *enumerator;
- NSData *part;
- NSMutableData *data;
-
- data = (self->useMimeData)
- ? [[[NGMimeJoinedData alloc] init] autorelease]
- : [NSMutableData dataWithCapacity:4096];
-
- enumerator = [_parts objectEnumerator];
- while ((part = [enumerator nextObject])) {
- [data appendBytes:"--" length:2];
- [data appendBytes:[_boundary cString] length:[_boundary length]];
- [data appendBytes:"\n" length:1];
- [data appendData:part];
- [data appendBytes:"\n" length:1];
- }
- [data appendBytes:"--" length:2];
- [data appendBytes:[_boundary cString] length:[_boundary length]];
- [data appendBytes:"--\n" length:3];
- return data;
-}
-
-- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
- additionalHeaders:(NGMutableHashMap *)_addHeaders
- delegate:(id)_delegate
-{
- // TODO: split up
- NGMimeMultipartBody *body = nil;
- NSMutableData *data = nil;
- id tmp = nil;
- NSArray *parts = nil;
- id<NGMimePart> part = nil;
- NSEnumerator *enumerator = nil;
- NSString *boundary = nil;
- NSMutableArray *partsData = nil;
- NSAutoreleasePool *pool;
-
- body = [_part body];
-
- if (body == nil)
- return [NSData data];
-
- pool = [[NSAutoreleasePool alloc] init];
-
- NSAssert1([body isKindOfClass:[NGMimeMultipartBody class]],
- @"NGMimeMultipartBodyGenerator expect a NGMimeMultipartBody "
- @"as body of part\n part: %@\n", _part);
-
- data = (self->useMimeData)
- ? [[[NGMimeJoinedData alloc] init] autorelease]
- : [NSMutableData dataWithCapacity:4096];
-
- if ([_delegate respondsToSelector:
- @selector(multipartBodyGenerator:prefixForPart:)])
- tmp = [_delegate multipartBodyGenerator:self prefixForPart:_part];
- else
- tmp = [self multipartBodyGenerator:self prefixForPart:_part
- mimeMultipart:body];
- if (tmp != nil) {
- NSAssert([tmp isKindOfClass:[NSString class]],
- @"prefix should be a NSString");
- [data appendBytes:[tmp cString] length:[tmp length]];
- }
-
- parts = [body parts];
- enumerator = [parts objectEnumerator];
- partsData = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:4];
-
- while ((part = [enumerator nextObject])) {
- id<NGMimePartGenerator> gen = nil;
-
- if ([_delegate respondsToSelector:
- @selector(multipartBodyGenerator:generatorForPart:)]) {
- gen = [_delegate multipartBodyGenerator:self generatorForPart:part];
- }
- else {
- gen = [self multipartBodyGenerator:self generatorForPart:part];
- [gen setDelegate:_delegate];
- [(id)gen setUseMimeData:self->useMimeData];
- }
- if (gen == nil) {
- NSLog(@"WARNING(%s): got no generator", __PRETTY_FUNCTION__);
- continue;
- }
- tmp = [gen generateMimeFromPart:part];
- if (tmp != nil) {
- [partsData addObject:tmp];
- }
- }
- boundary = [self buildBoundaryForPart:_part data:partsData
- additionalHeaders:_addHeaders];
- tmp = [self buildDataWithBoundary:boundary partsData:partsData];
-
- if (tmp != nil) {
- [data appendData:tmp];
- }
- else {
- NSLog(@"WARNING(%s): couldn`t build multipart data", __PRETTY_FUNCTION__);
- }
- if ([_delegate respondsToSelector:
- @selector(multipartBodyGenerator:suffixForPart:)])
- tmp = [_delegate multipartBodyGenerator:self suffixForPart:_part];
- else
- tmp = [self multipartBodyGenerator:self suffixForPart:_part
- mimeMultipart:body];
- if (tmp != nil) {
- NSAssert([tmp isKindOfClass:[NSString class]],
- @"suffix should be a NSString");
- [data appendBytes:[tmp cString] length:[tmp length]];
- }
- [partsData release]; partsData = nil;
- [data retain];
- [pool release];
- return [data autorelease];
-}
-
-- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
- prefixForPart:(id<NGMimePart>)_part
- mimeMultipart:(NGMimeMultipartBody *)_body {
-
- return @""; // [_body prefix];
-}
-
-- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
- suffixForPart:(id<NGMimePart>)_part
- mimeMultipart:(NGMimeMultipartBody *)_body {
-
- return @""; //[_body suffix];
-}
-
-- (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
- generatorForPart:(id<NGMimePart>)_part
-{
- id gen;
-
- gen = [[NGMimePartGenerator alloc] init];
- [gen setUseMimeData:self->useMimeData];
- return [gen autorelease];
-}
-
-@end /* NGMimeMultipartBodyGenerator */
if (type == nil) {
NSLog(@"WARNING(%s): empty content type field", __PRETTY_FUNCTION__);
- return [NSData dataWithBytes:"application/octet" length:17];
+ return [NSData dataWithBytes:"application/octet-stream" length:24];
}
if ([_value isKindOfClass:[NSString class]]) {
return [_value dataUsingEncoding:NSUTF8StringEncoding];
if (![type isKindOfClass:[NGMimeType class]]) {
NSLog(@"WARNING(%s): invalid MIME type value (%@) !", __PRETTY_FUNCTION__,
type);
- return [NSData dataWithBytes:"application/octet" length:17];
+ return [NSData dataWithBytes:"application/octet" length:24];
}
data = [NSMutableData dataWithCapacity:64];
#import <Foundation/NSData.h>
+/*
+ NGMimeJoinedData
+
+ TODO: explain.
+
+ Note: -copyWithZone: returns a _retained_ copy. Bug or feature?
+*/
+
@class NSMutableArray;
@interface NGMimeJoinedData : NSObject
[super dealloc];
}
-- (id)copyWithZone:(NSZone*)zone {
- return RETAIN(self);
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+ // TODO: we are mutable, is -retain a bug or feature?
+ return [self retain];
}
+/* data */
+
- (NSArray *)_joinedDataObjects {
return self->joinedDataObjects;
}
+- (unsigned int)length {
+ unsigned int i, count, size;
+
+ for (i = 0, count = [self->joinedDataObjects count], size = 0; i < count;i++)
+ size += [[self->joinedDataObjects objectAtIndex:i] length];
+ return size;
+}
+
+/* appending data */
+
- (void)appendData:(NSData *)_data {
if ([_data isKindOfClass:[NGMimeJoinedData class]]) {
[self->joinedDataObjects addObjectsFromArray:
[self->joinedDataObjects addObject:_data];
}
-- (void)appendBytes:(const void *)_bytes
- length:(unsigned int)_length
-{
+- (void)appendBytes:(const void *)_bytes length:(unsigned int)_length {
NSMutableData *data;
+ if (_length == 0)
+ return;
+
data = (NSMutableData *)[self->joinedDataObjects lastObject];
-
+
if ([data isKindOfClass:[NSMutableData class]]) {
[data appendBytes:_bytes length:_length];
}
else {
- data = [NSMutableData dataWithBytes:_bytes length:_length];
- [self->joinedDataObjects addObject:data];
+ /*
+ Note: we create a mutable because it is not unlikely that additional
+ appends are coming.
+ */
+ data = [[NSMutableData alloc] initWithBytes:_bytes length:_length];
+ if (data != nil) [self->joinedDataObjects addObject:data];
+ [data release];
}
}
-- (BOOL)writeToFile:(NSString*)_path
- atomically:(BOOL)_useAuxiliaryFile
-{
+/* writing to file */
+
+- (BOOL)writeToFile:(NSString*)_path atomically:(BOOL)_useAuxiliaryFile {
NSString *filename = nil;
NSEnumerator *enumerator;
NSData *data;
return result;
}
+/* description */
+
- (NSString *)description {
- return [NSString stringWithFormat:@"<0x%08X[%@]: joinedDataObjects=%d>",
- self, NSStringFromClass([self class]),
- [self->joinedDataObjects count]];
+ NSMutableString *ms;
+
+ ms = [NSMutableString stringWithCapacity:128];
+ [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
+ [ms appendFormat:@" joinedDataObjects=%d>",
+ [self->joinedDataObjects count]];
+ [ms appendString:@">"];
+ return ms;
}
@end /* NGMimeJoinedData */
--- /dev/null
+/*
+ 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 "NGMimeBodyGenerator.h"
+#include "NGMimePartGenerator.h"
+#include "NGMimeMultipartBody.h"
+#include "NGMimeJoinedData.h"
+#include "NGMimeFileData.h"
+#include "common.h"
+#include <unistd.h>
+
+@implementation NGMimeMultipartBodyGenerator
+
+static Class NGMimeFileDataClass = Nil;
+static Class NGMimeJoinedDataClass = Nil;
+static BOOL debugOn = NO;
+
++ (int)version {
+ return 2;
+}
++ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+ NSAssert2([super version] == 2,
+ @"invalid superclass (%@) version %i !",
+ NSStringFromClass([self superclass]), [super version]);
+
+ NGMimeFileDataClass = [NGMimeFileData class];
+ NGMimeJoinedDataClass = [NGMimeJoinedData class];
+
+ debugOn = [ud boolForKey:@"NGMimeGeneratorDebugEnabled"];
+ if (debugOn)
+ NSLog(@"WARNING[%@]: NGMimeGeneratorDebugEnabled is enabled!", self);
+}
+
++ (NSString *)boundaryPrefix {
+ static NSString *BoundaryPrefix = nil;
+
+ if (BoundaryPrefix == nil) {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+ BoundaryPrefix =
+ [[ud stringForKey:@"NGMime_MultipartBoundaryPrefix"] copy];
+ if (BoundaryPrefix == nil)
+ BoundaryPrefix = @"--=_=-_OpenGroupware_org_NGMime";
+ }
+ return BoundaryPrefix;
+}
+
+static inline BOOL _isBoundaryInArray(NGMimeMultipartBodyGenerator *self,
+ NSString *_boundary,
+ NSArray *_data)
+{
+ const unsigned char *boundary;
+ unsigned int length;
+ NSEnumerator *enumerator;
+ NSData *data;
+ BOOL wasFound;
+
+ // TODO: do we need to treat the boundary as a CString?
+ boundary = [_boundary cString];
+ length = [_boundary length];
+ enumerator = [_data objectEnumerator];
+ data = nil;
+ wasFound = NO;
+
+ while ((data = [enumerator nextObject]) != nil) {
+ const unsigned char *bytes;
+ unsigned int dataLen;
+ unsigned cnt;
+
+ if ([data isKindOfClass:NGMimeFileDataClass] ||
+ [data isKindOfClass:NGMimeJoinedDataClass])
+ continue;
+
+ bytes = [data bytes];
+ dataLen = [data length];
+ cnt = 0;
+
+ if (dataLen < length)
+ return NO;
+
+ while ((cnt < dataLen) && ((dataLen - cnt) >= length)) {
+ if (bytes[cnt + 2] != '-') { // can`t be a boundary
+ cnt++;
+ continue;
+ }
+
+ if (bytes[cnt] == '\n') {// LF*-
+ if (bytes[cnt + 1] == '-') { // LF--
+ if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
+ wasFound = YES;
+ break;
+ }
+ }
+ }
+ else if (bytes[cnt] == '\r') { //CR*-
+ if (bytes[cnt + 1] == '-') { //CR--
+ if (strncmp(boundary, bytes + cnt + 3, length) == 0) {
+ wasFound = YES;
+ break;
+ }
+ }
+ else if ((bytes[cnt + 1] == '\n') && (bytes[cnt + 3] == '-')) {
+ if (strncmp(boundary, bytes + cnt + 4, length) == 0) { // CRLF--
+ wasFound = YES;
+ break;
+ }
+ }
+ }
+ cnt++;
+ }
+ }
+ return wasFound;
+}
+
+- (NSString *)buildBoundaryForPart:(id<NGMimePart>)_part data:(NSArray *)_data
+ additionalHeaders:(NGMutableHashMap *)_addHeaders
+{
+ static int BoundaryUniqueCount = 0;
+ NSString *boundary = nil;
+ BOOL isUnique = NO;
+ unsigned pid;
+
+ if ((boundary = [[_part contentType] valueOfParameter:@"boundary"]))
+ return boundary;
+
+#if defined(__WIN32__)
+ pid = GetCurrentProcessId();
+#else
+ pid = getpid();
+#endif
+
+ boundary = [NSString stringWithFormat:
+ @"--%@-%d-%f-%d------",
+ [NGMimeMultipartBodyGenerator boundaryPrefix],
+ pid, [[NSDate date] timeIntervalSince1970],
+ BoundaryUniqueCount++];
+ while (!isUnique) {
+ isUnique = _isBoundaryInArray(self, boundary, _data) ? NO : YES;
+ if (!isUnique) {
+ boundary = [NSString stringWithFormat:
+ @"--%@-%d-%f-%d-----",
+ [NGMimeMultipartBodyGenerator boundaryPrefix],
+ pid, [[NSDate date] timeIntervalSince1970],
+ BoundaryUniqueCount++];
+ }
+ }
+ { // setting content-type with boundary
+ NGMimeType *type = nil;
+
+ type = [_part contentType];
+
+ if (type == nil) {
+ NSDictionary *d;
+
+ d = [[NSDictionary alloc] initWithObjectsAndKeys:
+ boundary, @"boundary", nil];
+ type = [NGMimeType mimeType:@"multipart" subType:@"mixed"
+ parameters:d];
+ [d release];
+ }
+ else {
+ NSMutableDictionary *dict = nil;
+
+ dict = [NSMutableDictionary dictionaryWithDictionary:
+ [type parametersAsDictionary]];
+ [dict setObject:boundary forKey:@"boundary"];
+ type = [NGMimeType mimeType:[type type] subType:[type subType]
+ parameters:dict];
+ }
+ [_addHeaders setObject:type forKey:@"content-type"];
+ }
+ return boundary;
+}
+
+- (NSData *)buildDataWithBoundary:(NSString *)_boundary
+ partsData:(NSArray *)_parts
+{
+ NSEnumerator *enumerator;
+ NSData *part;
+ NSMutableData *data;
+
+ data = (self->useMimeData)
+ ? [[[NGMimeJoinedData alloc] init] autorelease]
+ : [NSMutableData dataWithCapacity:4096];
+
+ enumerator = [_parts objectEnumerator];
+ while ((part = [enumerator nextObject])) {
+ [data appendBytes:"--" length:2];
+ [data appendBytes:[_boundary cString] length:[_boundary length]];
+ [data appendBytes:"\n" length:1];
+ [data appendData:part];
+ [data appendBytes:"\n" length:1];
+ }
+ [data appendBytes:"--" length:2];
+ [data appendBytes:[_boundary cString] length:[_boundary length]];
+ [data appendBytes:"--\n" length:3];
+ return data;
+}
+
+- (NSData *)generateBodyOfPart:(id<NGMimePart>)_part
+ additionalHeaders:(NGMutableHashMap *)_addHeaders
+ delegate:(id)_delegate
+{
+ // TODO: split up
+ NGMimeMultipartBody *body = nil;
+ NSMutableData *data = nil;
+ id tmp = nil;
+ NSArray *parts = nil;
+ id<NGMimePart> part = nil;
+ NSEnumerator *enumerator = nil;
+ NSString *boundary = nil;
+ NSMutableArray *partsData = nil;
+ NSAutoreleasePool *pool;
+
+ body = [_part body];
+
+ if (body == nil)
+ return [NSData data];
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ NSAssert1([body isKindOfClass:[NGMimeMultipartBody class]],
+ @"NGMimeMultipartBodyGenerator expect a NGMimeMultipartBody "
+ @"as body of part\n part: %@\n", _part);
+
+ data = (self->useMimeData)
+ ? [[[NGMimeJoinedData alloc] init] autorelease]
+ : [NSMutableData dataWithCapacity:4096];
+
+ if ([_delegate respondsToSelector:
+ @selector(multipartBodyGenerator:prefixForPart:)])
+ tmp = [_delegate multipartBodyGenerator:self prefixForPart:_part];
+ else
+ tmp = [self multipartBodyGenerator:self prefixForPart:_part
+ mimeMultipart:body];
+ if (tmp != nil) {
+ NSAssert([tmp isKindOfClass:[NSString class]],
+ @"prefix should be a NSString");
+ [data appendBytes:[tmp cString] length:[tmp length]];
+ }
+
+ parts = [body parts];
+ enumerator = [parts objectEnumerator];
+ partsData = [[NSMutableArray alloc] initWithCapacity:4];
+
+ while ((part = [enumerator nextObject]) != nil) {
+ id<NGMimePartGenerator> gen = nil;
+ NSData *data;
+
+ if ([_delegate respondsToSelector:
+ @selector(multipartBodyGenerator:generatorForPart:)]) {
+ gen = [_delegate multipartBodyGenerator:self generatorForPart:part];
+ }
+ else {
+ gen = [self multipartBodyGenerator:self generatorForPart:part];
+ [gen setDelegate:_delegate];
+ [(id)gen setUseMimeData:self->useMimeData];
+ }
+ if (gen == nil) {
+ [self logWithFormat:@"WARNING(%s): got no generator",
+ __PRETTY_FUNCTION__];
+ continue;
+ }
+
+ /* generate part */
+
+ data = [gen generateMimeFromPart:part];
+ if (data != nil) {
+ if (debugOn) {
+ [self debugWithFormat:
+ @"multipart body generated %d bytes using %@ for part: %@",
+ [data length], gen, part];
+ }
+ [partsData addObject:data];
+ }
+ else if (debugOn) {
+ [self debugWithFormat:
+ @"multipart body %@ did not generate content for part: %@",
+ gen, part];
+ }
+ }
+ boundary = [self buildBoundaryForPart:_part data:partsData
+ additionalHeaders:_addHeaders];
+ tmp = [self buildDataWithBoundary:boundary partsData:partsData];
+
+ if (tmp != nil) {
+ [data appendData:tmp];
+ }
+ else {
+ NSLog(@"WARNING(%s): couldn`t build multipart data", __PRETTY_FUNCTION__);
+ }
+ if ([_delegate respondsToSelector:
+ @selector(multipartBodyGenerator:suffixForPart:)])
+ tmp = [_delegate multipartBodyGenerator:self suffixForPart:_part];
+ else
+ tmp = [self multipartBodyGenerator:self suffixForPart:_part
+ mimeMultipart:body];
+ if (tmp != nil) {
+ NSAssert([tmp isKindOfClass:[NSString class]],
+ @"suffix should be a NSString");
+ [data appendBytes:[tmp cString] length:[tmp length]];
+ }
+ [partsData release]; partsData = nil;
+ [data retain];
+ [pool release];
+ return [data autorelease];
+}
+
+- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
+ prefixForPart:(id<NGMimePart>)_part
+ mimeMultipart:(NGMimeMultipartBody *)_body
+{
+ return @""; // [_body prefix];
+}
+
+- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen
+ suffixForPart:(id<NGMimePart>)_part
+ mimeMultipart:(NGMimeMultipartBody *)_body
+{
+ return @""; //[_body suffix];
+}
+
+- (id<NGMimePartGenerator>)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen
+ generatorForPart:(id<NGMimePart>)_part
+{
+ id gen;
+
+ gen = [[NGMimePartGenerator alloc] init];
+ [gen setUseMimeData:self->useMimeData];
+ return [gen autorelease];
+}
+
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+ return debugOn;
+}
+
+@end /* NGMimeMultipartBodyGenerator */
@implementation NGMimePartGenerator
+static NSProcessInfo *Pi = nil;
+static BOOL debugOn = NO;
+
+ (int)version {
return 2;
}
++ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+ debugOn = [ud boolForKey:@"NGMimeGeneratorDebugEnabled"];
+ if (debugOn)
+ NSLog(@"WARNING[%@]: NGMimeGeneratorDebugEnabled is enabled!", self);
+
+ if (Pi == nil)
+ Pi = [[NSProcessInfo processInfo] retain];
+}
+ (id)mimePartGenerator {
return [[[self alloc] init] autorelease];
self->delegateRespondsTo.generatorGenerateDataForBodyOfPart =
[self->delegate respondsToSelector:
- @selector(mimePartGenerator:generateDataForBodyOfPart:additionalHeaders:)];
+ @selector(mimePartGenerator:generateDataForBodyOfPart:additionalHeaders:)];
}
- (id)delegate {
}
- (BOOL)prepareForGenerationOfPart:(id<NGMimePart>)_part {
- {
- id tmp = self->part;
-
- self->part = _part;
-
- [self->part retain];
- [tmp release]; tmp = nil;
- }
+ ASSIGN(self->part, _part);
+
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:)])
+ 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;
}
- (NGMimeType *)defaultContentTypeForPart:(id<NGMimePart>)_part {
- return [NGMimeType mimeType:@"application/octet"];
+ return [NGMimeType mimeType:@"application/octet-stream"];
}
- (id<NGMimeBodyGenerator>)defaultBodyGenerator {
NGMimeType *contentType = nil;
NSString *type = nil;
- if (self->delegateRespondsTo.generatorGeneratorForBodyOfPart)
+ if (self->delegateRespondsTo.generatorGeneratorForBodyOfPart) {
bodyGen = [self->delegate mimePartGenerator:self
generatorForBodyOfPart:self->part];
-
- if (!bodyGen) {
+ }
+
+ if (bodyGen == nil) {
contentType = [_part contentType];
- if (contentType == nil) {
+ if (contentType == nil)
contentType = [self defaultContentTypeForPart:_part];
- }
+
if (contentType == nil) {
- NSLog(@"WARNING(%s): no content-type", __PRETTY_FUNCTION__);
+ [self logWithFormat:@"WARNING(%s): no content-type",__PRETTY_FUNCTION__];
return nil;
}
type = [contentType type];
-
+
if ([type isEqualToString:NGMimeTypeMultipart]) {
bodyGen = [[[NGMimeMultipartBodyGenerator alloc] init] autorelease];
}
- (NSData *)generateBodyData:(NGMutableHashMap *)_additionalHeaders {
NSData *data = nil;
id<NGMimeBodyGenerator> bodyGen = nil;
-
+ id body;
+
+ /* ask delegate whether it wants to deal with the part */
+
if (self->delegateRespondsTo.generatorGenerateDataForBodyOfPart) {
data = [self->delegate mimePartGenerator:self
generateDataForBodyOfPart:self->part
additionalHeaders:_additionalHeaders];
+ return data;
}
- else {
- bodyGen = [self generatorForBodyOfPart:self->part];
- if (bodyGen == nil) // no generator for body
- bodyGen = [self defaultBodyGenerator];
+ /* lookup generator object or use default generator */
- [(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];
+ bodyGen = [self generatorForBodyOfPart:self->part];
+ if (bodyGen == nil) { /* no generator for body */
+ bodyGen = [self defaultBodyGenerator];
+ if (debugOn) {
+ [self debugWithFormat:@"Note: using default generator %@ for part: %@",
+ bodyGen, self->part];
}
}
+
+ [(id)bodyGen setUseMimeData:self->useMimeData];
+
+ /* generate */
+
+ if (bodyGen != nil) {
+ data = [bodyGen generateBodyOfPart:self->part
+ additionalHeaders:_additionalHeaders
+ delegate:self->delegate];
+ return data;
+ }
+
+ /* fallback, try to encode NSString and NSData objects */
+
+ body = [self->part body];
+ [self logWithFormat:@"WARNING(%s): class has no defaultBodyGenerator",
+ __PRETTY_FUNCTION__];
+
+ if ([body isKindOfClass:[NSData class]])
+ data = body;
+ else if ([body isKindOfClass:[NSString class]])
+ data = [body dataUsingEncoding:[NSString defaultCStringEncoding]];
+ else
+ data = nil;
+
return data;
}
- (void)generateData {
- NGMutableHashMap *additionalHeaders = nil;
- NSData *bodyData = nil;
- NSData *headerData = nil;
+ NGMutableHashMap *additionalHeaders;
+ NSData *bodyData;
+ NSData *headerData;
+ /* the body generator will fill in headers if required */
additionalHeaders = [[NGMutableHashMap alloc] initWithCapacity:16];
+
+ if (debugOn) {
+ [self debugWithFormat:@"generate part: 0x%08X<%@>",
+ self->part, NSStringFromClass([self->part class])];
+ }
+
+ bodyData = [self generateBodyData:additionalHeaders];
+ if (debugOn) {
+ [self debugWithFormat:@" => body 0x%08X<%@> length=%d",
+ bodyData, NSStringFromClass([bodyData class]), [bodyData length]];
+ }
- bodyData = [self generateBodyData:additionalHeaders];
headerData = [self generateHeaderData:additionalHeaders];
-
+ if (debugOn) {
+ [self debugWithFormat:@" => header 0x%08X<%@> length=%d",
+ headerData, NSStringFromClass([headerData class]),
+ [headerData length]];
+ }
+
if (headerData != nil) {
- [self->result appendData:headerData];
- [self->result appendBytes:"\n" length:1];
+ // TODO: length check is new, this should be correct, but might be wrong.
+ // Some strange things occur if we generate a part which is a
+ // NGMimeFileData (this method was called twiced, once without header
+ // data which in turn resulted in a superflous "\r\n" string
+ if ([headerData length] > 0) {
+ [self->result appendData:headerData];
+ [self->result appendBytes:"\r\n" length:2];
+ }
+
if (bodyData != nil)
[self->result appendData:bodyData];
+ else if (debugOn)
+ [self debugWithFormat:@" => did not generate any body data!"];
}
- [additionalHeaders release];
+ else if (debugOn)
+ [self debugWithFormat:@" => did not generate any header data!"];
+
+ [additionalHeaders release]; additionalHeaders = nil;
}
- (NSData *)generateMimeFromPart:(id<NGMimePart>)_part {
+ NSData *data;
+
[self prepareForGenerationOfPart:_part];
- if ([self generatePrefix]) {
- NSData *data;
+ if (![self generatePrefix])
+ return nil;
- [self generateData];
- [self generateSuffix];
- data = self->result;
- self->result = nil;
- return [data autorelease];
- }
- return nil;
+ [self generateData];
+ [self generateSuffix];
+ data = self->result;
+ self->result = nil;
+ return [data autorelease];
}
- (NSString *)generateMimeFromPartToFile:(id<NGMimePart>)_part {
NSString *filename = nil;
static NSString *TmpPath = nil;
- static NSProcessInfo *Pi = nil;
if (TmpPath == nil) {
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
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]
return self->part;
}
+- (void)setUseMimeData:(BOOL)_b {
+ self->useMimeData = _b;
+}
- (BOOL)useMimeData {
return self->useMimeData;
}
-- (void)setUseMimeData:(BOOL)_b {
- self->useMimeData = _b;
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+ return debugOn;
}
@end /* NGMimePartGenerator */
-
- (NGMimeType *)contentType {
static NGMimeType *defType = nil;
if (defType == nil)
- defType = [[NGMimeType mimeType:@"application/octet"] retain];
+ defType = [[NGMimeType mimeType:@"application/octet-stream"] retain];
return defType;
}
- (NSString *)contentId {
MAJOR_VERSION:=4
MINOR_VERSION:=5
-SUBMINOR_VERSION:=205
+SUBMINOR_VERSION:=206
# v4.2.149 requires libNGStreams v4.2.34