mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Make GSMime more tolerant
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@15109 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
62b716613d
commit
c8a6fe63e2
3 changed files with 112 additions and 85 deletions
|
@ -3,6 +3,9 @@
|
|||
* Source/Additions/GCObject.m: Attempt to make garbage collecting
|
||||
thread-safe.
|
||||
* Source/Additions/GCArray.m: Fix count initialising mutable array.
|
||||
* Source/Additions/GSMime.m: Provide a method to generate and return
|
||||
a string suitable for use as a boundary. Make tolerant of multipart
|
||||
messages with 'application' as the message type.
|
||||
|
||||
2002-11-25 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
- (void) deleteHeaderNamed: (NSString*)name;
|
||||
- (GSMimeHeader*) headerNamed: (NSString*)name;
|
||||
- (NSArray*) headersNamed: (NSString*)name;
|
||||
- (NSString*) makeBoundary;
|
||||
- (GSMimeHeader*) makeContentID;
|
||||
- (GSMimeHeader*) makeMessageID;
|
||||
- (NSMutableData*) rawMimeData;
|
||||
|
@ -129,7 +130,7 @@
|
|||
name: (NSString*)name;
|
||||
- (void) setContent: (id)newContent
|
||||
type: (NSString*)type
|
||||
subType: (NSString*)subType
|
||||
subtype: (NSString*)subType
|
||||
name: (NSString*)name;
|
||||
- (void) setHeader: (GSMimeHeader*)info;
|
||||
|
||||
|
|
|
@ -55,12 +55,22 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static NSString *makeUniqueString();
|
||||
|
||||
static NSCharacterSet *whitespace = nil;
|
||||
static NSCharacterSet *rfc822Specials = nil;
|
||||
static NSCharacterSet *rfc2045Specials = nil;
|
||||
|
||||
struct MD5Context
|
||||
{
|
||||
unsigned long buf[4];
|
||||
unsigned long bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
static void MD5Init (struct MD5Context *context);
|
||||
static void MD5Update (struct MD5Context *context, unsigned char const *buf,
|
||||
unsigned len);
|
||||
static void MD5Final (unsigned char digest[16], struct MD5Context *context);
|
||||
static void MD5Transform (unsigned long buf[4], unsigned long const in[16]);
|
||||
|
||||
/*
|
||||
* Name - decodebase64()
|
||||
* Purpose - Convert 4 bytes in base64 encoding to 3 bytes raw data.
|
||||
|
@ -1377,11 +1387,23 @@ wordData(NSString *word)
|
|||
}
|
||||
else if ([name isEqualToString: @"content-type"] == YES)
|
||||
{
|
||||
NSString *tmp = [info parameterForKey: @"boundary"];
|
||||
NSString *type;
|
||||
NSString *subtype;
|
||||
BOOL supported = NO;
|
||||
|
||||
DESTROY(boundary);
|
||||
if (tmp != nil)
|
||||
{
|
||||
unsigned int l = [tmp cStringLength] + 2;
|
||||
unsigned char *b = NSZoneMalloc(NSDefaultMallocZone(), l + 1);
|
||||
|
||||
b[0] = '-';
|
||||
b[1] = '-';
|
||||
[tmp getCString: &b[2]];
|
||||
boundary = [[NSData alloc] initWithBytesNoCopy: b length: l];
|
||||
}
|
||||
|
||||
type = [info objectForKey: @"Type"];
|
||||
if ([type length] == 0)
|
||||
{
|
||||
|
@ -1399,24 +1421,12 @@ wordData(NSString *word)
|
|||
}
|
||||
else if ([type isEqualToString: @"multipart"] == YES)
|
||||
{
|
||||
NSString *tmp = [info parameterForKey: @"boundary"];
|
||||
|
||||
if (subtype == nil)
|
||||
{
|
||||
subtype = @"mixed";
|
||||
}
|
||||
supported = YES;
|
||||
if (tmp != nil)
|
||||
{
|
||||
unsigned int l = [tmp cStringLength] + 2;
|
||||
unsigned char *b = NSZoneMalloc(NSDefaultMallocZone(), l + 1);
|
||||
|
||||
b[0] = '-';
|
||||
b[1] = '-';
|
||||
[tmp getCString: &b[2]];
|
||||
boundary = [[NSData alloc] initWithBytesNoCopy: b length: l];
|
||||
}
|
||||
else
|
||||
if (boundary == nil)
|
||||
{
|
||||
NSLog(@"multipart message without boundary");
|
||||
return NO;
|
||||
|
@ -3653,6 +3663,44 @@ static NSCharacterSet *tokenSet = nil;
|
|||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a probably unique string suitable for use as the
|
||||
* boundary parameter in the content of a multipart document.
|
||||
* </p>
|
||||
* <p>This implementation provides base64 encoded data
|
||||
* consisting of an MD5 digest of some pseudo random stuff,
|
||||
* plus an incrementing counter.
|
||||
* </p>
|
||||
*/
|
||||
- (NSString*) makeBoundary
|
||||
{
|
||||
static int count = 0;
|
||||
struct MD5Context ctx;
|
||||
const char *bytes;
|
||||
unsigned int i;
|
||||
unsigned char digest[20];
|
||||
unsigned char *encoded;
|
||||
NSMutableData *md;
|
||||
NSString *result;
|
||||
|
||||
md = [[NSMutableData alloc] initWithLength: 40];
|
||||
encoded = (unsigned char*)[md mutableBytes];
|
||||
MD5Init(&ctx);
|
||||
bytes = [[[NSProcessInfo processInfo] globallyUniqueString] lossyCString];
|
||||
MD5Update(&ctx, bytes, strlen(bytes));
|
||||
count++;
|
||||
MD5Update(&ctx, (unsigned char*)&count, sizeof(count));
|
||||
MD5Final(digest, &ctx);
|
||||
digest[16] = (count >> 24) & 0xff;
|
||||
digest[17] = (count >> 16) & 0xff;
|
||||
digest[18] = (count >> 8) & 0xff;
|
||||
digest[19] = count & 0xff;
|
||||
i = encodebase64(encoded, digest, 20);
|
||||
[md setLength: i];
|
||||
result = [[NSString alloc] initWithData: md encoding: NSASCIIStringEncoding];
|
||||
return AUTORELEASE(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new content ID header, set it as the content ID of the document
|
||||
* and return it.<br />
|
||||
|
@ -3719,6 +3767,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
GSMimeHeader *hdr;
|
||||
NSData *boundary;
|
||||
BOOL is7bit = YES;
|
||||
BOOL isMultipart = NO;
|
||||
|
||||
if (isOuter == YES)
|
||||
{
|
||||
|
@ -3737,32 +3786,36 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
}
|
||||
|
||||
if ([content isKindOfClass: [NSArray class]] == YES)
|
||||
{
|
||||
isMultipart = YES;
|
||||
}
|
||||
|
||||
type = [self headerNamed: @"content-type"];
|
||||
if (type == nil)
|
||||
{
|
||||
/*
|
||||
* Attempt to infer the content type from the content.
|
||||
*/
|
||||
if ([content isKindOfClass: [NSString class]] == YES)
|
||||
if (isMultipart == YES)
|
||||
{
|
||||
[self setContent: content
|
||||
type: @"multipart"
|
||||
subtype: @"mixed"
|
||||
name: nil];
|
||||
}
|
||||
else if ([content isKindOfClass: [NSString class]] == YES)
|
||||
{
|
||||
[self setContent: content
|
||||
type: @"text"
|
||||
subType: @"plain"
|
||||
subtype: @"plain"
|
||||
name: nil];
|
||||
}
|
||||
else if ([content isKindOfClass: [NSData class]] == YES)
|
||||
{
|
||||
[self setContent: content
|
||||
type: @"application"
|
||||
subType: @"octet-stream"
|
||||
name: nil];
|
||||
}
|
||||
else if ([content isKindOfClass: [NSArray class]] == YES
|
||||
&& [content count] > 0)
|
||||
{
|
||||
[self setContent: content
|
||||
type: @"multipart"
|
||||
subType: @"mixed"
|
||||
subtype: @"octet-stream"
|
||||
name: nil];
|
||||
}
|
||||
else
|
||||
|
@ -3774,7 +3827,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
type = [self headerNamed: @"content-type"];
|
||||
}
|
||||
|
||||
if ([[type objectForKey: @"Type"] isEqual: @"multipart"] == YES)
|
||||
if (isMultipart == YES)
|
||||
{
|
||||
NSString *v;
|
||||
|
||||
|
@ -3803,7 +3856,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
v = [type parameterForKey: @"boundary"];
|
||||
if (v == nil)
|
||||
{
|
||||
v = makeUniqueString();
|
||||
v = [self makeBoundary];
|
||||
[type setParameter: v forKey: @"boundary"];
|
||||
}
|
||||
boundary = [v dataUsingEncoding: NSASCIIStringEncoding];
|
||||
|
@ -3857,7 +3910,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
[md appendData: [hdr rawMimeData]];
|
||||
}
|
||||
|
||||
if ([[type objectForKey: @"Type"] isEqual: @"multipart"] == YES)
|
||||
if (isMultipart == YES)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned i;
|
||||
|
@ -3978,7 +4031,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
|
||||
/**
|
||||
* Convenience method calling -setContent:type:subType:name: to set
|
||||
* Convenience method calling -setContent:type:subtype:name: to set
|
||||
* content and type. If the type argument contains a slash '/')
|
||||
* then it is split into type and subtype parts, otherwise, the
|
||||
* subtype is assumed to be nil.
|
||||
|
@ -4014,28 +4067,45 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
[self setContent: newContent
|
||||
type: type
|
||||
subType: subtype
|
||||
subtype: subtype
|
||||
name: name];
|
||||
}
|
||||
|
||||
- (void) setContent: (id)newContent
|
||||
type: (NSString*)type
|
||||
subType: (NSString*)subtype
|
||||
name: (NSString*)name
|
||||
{
|
||||
[self setContent: newContent type: type subtype: subtype name: name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to set the content of the document along with
|
||||
* creating a content-type header for it.<br />
|
||||
* You can get the same effect by calling -setContent: to set the document
|
||||
* <p>Convenience method to set the content of the document along with
|
||||
* creating a content-type header for it.
|
||||
* </p>
|
||||
* <p>You can get the same effect by calling -setContent: to set the document
|
||||
* content, then creating a [GSMimeHeader] instance, initialising it with
|
||||
* the content type information you want using
|
||||
* [GSMimeHeader-initWithName:value:parameters:], and calling the
|
||||
* -setHeader: method to attach it to the document.
|
||||
* </p>
|
||||
* <p>Using this method imposes a few extra checks and restrictions on the
|
||||
* combination of content and type/subtype you may use ... so you may want
|
||||
* to use the more primitive methods in order to bypass these checks if
|
||||
* you are using unusual type/subtype information or if you need to provide
|
||||
* additional paramters in the header.
|
||||
* </p>
|
||||
*/
|
||||
- (void) setContent: (id)newContent
|
||||
type: (NSString*)type
|
||||
subType: (NSString*)subType
|
||||
subtype: (NSString*)subtype
|
||||
name: (NSString*)name
|
||||
{
|
||||
GSMimeHeader *hdr;
|
||||
NSString *val;
|
||||
|
||||
if ([type isEqualToString: @"multipart"] == NO
|
||||
&& [type isEqualToString: @"application"] == NO
|
||||
&& [content isKindOfClass: [NSArray class]] == YES)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
|
@ -4045,11 +4115,11 @@ static NSCharacterSet *tokenSet = nil;
|
|||
|
||||
[self setContent: newContent];
|
||||
|
||||
val = [NSString stringWithFormat: @"%@/%@", type, subType];
|
||||
val = [NSString stringWithFormat: @"%@/%@", type, subtype];
|
||||
hdr = [GSMimeHeader alloc];
|
||||
hdr = [hdr initWithName: @"content-type" value: val parameters: nil];
|
||||
[hdr setObject: type forKey: @"Type"];
|
||||
[hdr setObject: subType forKey: @"SubType"];
|
||||
[hdr setObject: subtype forKey: @"SubType"];
|
||||
if (name != nil)
|
||||
{
|
||||
[hdr setParameter: name forKey: @"name"];
|
||||
|
@ -4120,18 +4190,6 @@ static NSCharacterSet *tokenSet = nil;
|
|||
|
||||
#include <Foundation/NSByteOrder.h>
|
||||
|
||||
struct MD5Context
|
||||
{
|
||||
unsigned long buf[4];
|
||||
unsigned long bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
static void MD5Init (struct MD5Context *context);
|
||||
static void MD5Update (struct MD5Context *context, unsigned char const *buf,
|
||||
unsigned len);
|
||||
static void MD5Final (unsigned char digest[16], struct MD5Context *context);
|
||||
static void MD5Transform (unsigned long buf[4], unsigned long const in[16]);
|
||||
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
|
@ -4379,38 +4437,3 @@ static void MD5Transform (unsigned long buf[4], unsigned long const in[16])
|
|||
buf[3] += d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a probably unique string of base64 encoded data
|
||||
* consisting of an MD5 digest of some pseudo random stuff,
|
||||
* plus an incrementing counter.
|
||||
*/
|
||||
static NSString *
|
||||
makeUniqueString()
|
||||
{
|
||||
static int count = 0;
|
||||
struct MD5Context ctx;
|
||||
const char *bytes;
|
||||
unsigned int i;
|
||||
unsigned char digest[20];
|
||||
unsigned char *encoded;
|
||||
NSMutableData *md;
|
||||
NSString *result;
|
||||
|
||||
md = [[NSMutableData alloc] initWithLength: 40];
|
||||
encoded = (unsigned char*)[md mutableBytes];
|
||||
MD5Init(&ctx);
|
||||
bytes = [[[NSProcessInfo processInfo] globallyUniqueString] lossyCString];
|
||||
MD5Update(&ctx, bytes, strlen(bytes));
|
||||
count++;
|
||||
MD5Update(&ctx, (unsigned char*)&count, sizeof(count));
|
||||
MD5Final(digest, &ctx);
|
||||
digest[16] = (count >> 24) & 0xff;
|
||||
digest[17] = (count >> 16) & 0xff;
|
||||
digest[18] = (count >> 8) & 0xff;
|
||||
digest[19] = count & 0xff;
|
||||
i = encodebase64(encoded, digest, 20);
|
||||
[md setLength: i];
|
||||
result = [[NSString alloc] initWithData: md encoding: NSASCIIStringEncoding];
|
||||
return AUTORELEASE(result);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue