]> err.no Git - sope/commitdiff
major change to MIME generation, a lot of cleanups
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 30 Jan 2005 19:33:33 +0000 (19:33 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 30 Jan 2005 19:33:33 +0000 (19:33 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@534 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

21 files changed:
sope-mime/ChangeLog
sope-mime/NGImap4/ChangeLog
sope-mime/NGImap4/NGImap4Client.m
sope-mime/NGImap4/NGImap4Folder.m
sope-mime/NGMail/ChangeLog
sope-mime/NGMail/GNUmakefile
sope-mime/NGMail/NGMailBase64Encoding.m [new file with mode: 0644]
sope-mime/NGMail/NGMimeMessage.m
sope-mime/NGMail/NGMimeMessageBodyGenerator.m
sope-mime/NGMail/NGMimeMessageGenerator.m
sope-mime/NGMail/NGMimeMessageParser.m
sope-mime/NGMime/ChangeLog
sope-mime/NGMime/GNUmakefile
sope-mime/NGMime/NGMimeBodyGenerator.m
sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m
sope-mime/NGMime/NGMimeJoinedData.h
sope-mime/NGMime/NGMimeJoinedData.m
sope-mime/NGMime/NGMimeMultipartBodyGenerator.m [new file with mode: 0644]
sope-mime/NGMime/NGMimePartGenerator.m
sope-mime/NGMime/NGPart.m
sope-mime/Version

index 058be256d0c24b788fad02af1e2803a7894cb1bc..c047e104cdc29ee72677d0f04bc6d0981ebb1de5 100644 (file)
@@ -1,3 +1,15 @@
+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)
index 11cf5b7984e824351d3866860f5e5b8190d5777b..66b1316deeb1ec69aa2112975c483e5ef8c95172 100644 (file)
@@ -1,3 +1,7 @@
+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
index 429cc073d4343fd67d2b47de8e6d606230b33786..cf3059b52aee6f2d5496c97ddeb5c8ee7ffc31a6 100644 (file)
@@ -873,24 +873,25 @@ static BOOL         ImapDebugEnabled   = NO;
     
     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}",
@@ -900,6 +901,7 @@ static BOOL         ImapDebugEnabled   = NO;
   result = [self processCommand:icmd
                  withTag:YES withNotification:NO];
   
+  // TODO: explain that
   if ([[result objectForKey:@"ContinuationResponse"] boolValue])
     result = [self processCommand:message withTag:NO];
 
index 4cffb67e3aa7301f3cb79f96d7d9c276b129191c..4c6af2c184c293485d9cb81a95b535ccf1cd6019 100644 (file)
@@ -1200,7 +1200,7 @@ static int FetchNewUnseenMessagesInSubFoldersOnDemand = -1;
       return YES;
   }
   [self resetLastException];
-
+  
   dict = [[self->context client] select:[self absoluteName]];
   if (![self _checkResult:dict cmd:__PRETTY_FUNCTION__]) {
     self->failedFlags.select = YES;
index ae6b0005f77718eac11af811523d89ef5c2a520c..009fae086b93a18f77120da5214d84f4354b3bf1 100644 (file)
@@ -1,3 +1,9 @@
+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
index 5f250f5f3e27e2c72dc2e7c4bf121d6b2fc7a63a..1d1cd0411c88f0c1c0eb7d65e105cb2876d71961 100644 (file)
@@ -45,6 +45,8 @@ NGMail_OBJC_FILES = \
        NGMimeMessageMultipartBodyGenerator.m   \
        NGMimeMessageRfc822BodyGenerator.m      \
        NGMimeMessageTextBodyGenerator.m        \
+       \
+       NGMailBase64Encoding.m  \
 
 -include GNUmakefile.preamble
 include $(GNUSTEP_MAKEFILES)/subproject.make
diff --git a/sope-mime/NGMail/NGMailBase64Encoding.m b/sope-mime/NGMail/NGMailBase64Encoding.m
new file mode 100644 (file)
index 0000000..f4554c1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  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_;
+}
index d058d15c482a0f7c317bf527d49528e93da0bdff..38b85102df09ba48377e705bc11276472ccbb618 100644 (file)
@@ -67,9 +67,9 @@ static NGMimeType *defaultDataType = nil;
 /* 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 {
@@ -87,29 +87,22 @@ static NGMimeType *defaultDataType = nil;
 /* 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 {
index f897d0ef7ea112a54b4cc06ae09b3ff3b41243ed..0f176bb772bc61cf1bc49f68243db515088c42db 100644 (file)
@@ -34,6 +34,8 @@
             NSStringFromClass([self superclass]), [super version]);
 }
 
+/* encoding data */
+
 - (NSData *)encodeData:(NSData *)_data
   forPart:(id<NGMimePart>)_part
   additionalHeaders:(NGMutableHashMap *)_addHeaders
index 6026bd4e4c32dd64344a6432071c4aedb9b40f87..415b34c309b5396e5b7653671bb59ea31f82b052 100644 (file)
 #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 */
@@ -181,6 +121,7 @@ _base64Encoding(NGMimeBodyGenerator *self,
 }
 
 - (id<NGMimeBodyGenerator>)generatorForBodyOfPart:(id<NGMimePart>)_part {
+  /* called by -generateBodyData:? */
   id<NGMimeBodyGenerator> bodyGen;
   NGMimeType              *contentType;
   NSString                *type;
@@ -198,7 +139,8 @@ _base64Encoding(NGMimeBodyGenerator *self,
     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;
   }
   
@@ -213,10 +155,30 @@ _base64Encoding(NGMimeBodyGenerator *self,
            [[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 */
index 692538d161f5656d4e6aa1b0200fe4ff91a03132..c373c151c9f6cd36b09573a972e526661daaec63 100644 (file)
@@ -273,7 +273,7 @@ static Class NSStringClass = Nil;
         }
       }
     }
-    if (appendLC == YES) {
+    if (appendLC) {
       if (cnt < length) {
         buffer[bufLen] = bytes[cnt];
         bufLen++;
index 351c7ee87ffd31b70aae9c35600dc0968a4d99df..fbba16db4faa4a83135ded58c6a3ec27f3828a97 100644 (file)
@@ -1,3 +1,21 @@
+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
index 7165de9e0ff7cd29f7226c8da43eeb67be1b72ef..77a84140ca2e16cc67afc1bbfbd0d95f6654e518 100644 (file)
@@ -69,6 +69,8 @@ NGMime_OBJC_FILES = \
        NGMimeHeaderFieldGeneratorSet.m                 \
        NGMimeRFC822DateHeaderFieldGenerator.m          \
        NGMimeStringHeaderFieldGenerator.m              \
+       \
+       NGMimeMultipartBodyGenerator.m                  \
 
 -include GNUmakefile.preamble
 include $(GNUSTEP_MAKEFILES)/subproject.make
index 28e755a0b8a6537787101560fdb6b7eb486d5193..9c687f11e48fc1dd8e1600902a72aefc33a5f79b 100644 (file)
   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 */
index 395fe64d0faa7a8301b49fd8bfdf7d9511fe1543..5fba916f568d8e2d517943dbc44317774a23f018 100644 (file)
@@ -42,7 +42,7 @@
 
   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];
@@ -51,7 +51,7 @@
   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];
index 192fc780b2ddb9c547f685dbbd89a535ecd101ed..1af6a8be29f654be340d03217ee77c387dd8387d 100644 (file)
 
 #import <Foundation/NSData.h>
 
+/*
+  NGMimeJoinedData
+  
+  TODO: explain.
+
+  Note: -copyWithZone: returns a _retained_ copy. Bug or feature?
+*/
+
 @class NSMutableArray;
 
 @interface NGMimeJoinedData : NSObject
index 9b4375ea87a2538e1dd20ef5689bb3e1e9a71215..83c450c7e051ea0017a7723acc1c7a91c13c8baf 100644 (file)
   [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 */
diff --git a/sope-mime/NGMime/NGMimeMultipartBodyGenerator.m b/sope-mime/NGMime/NGMimeMultipartBodyGenerator.m
new file mode 100644 (file)
index 0000000..4c0a78f
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+  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 */
index 6be526f23d7249ad38b35dd10cc2280cb6f7d853..d3793f6c0c97638775f391ff46339a9602905973 100644 (file)
 
 @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];
@@ -67,7 +80,7 @@
   
   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 */
-  
index 80010450785c1dc236f7031e77c64746d130ed31..344d9e0ff9cabb11adc7545e31f3fe3b33498d70 100644 (file)
@@ -68,7 +68,7 @@
 - (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 {
index 7c6993739c655e462e164cd24d99d194caa8c680..74d1c71b3eb2d2568a1777462a089b76c39b45eb 100644 (file)
@@ -2,6 +2,6 @@
 
 MAJOR_VERSION:=4
 MINOR_VERSION:=5
-SUBMINOR_VERSION:=205
+SUBMINOR_VERSION:=206
 
 # v4.2.149 requires libNGStreams v4.2.34