mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +00:00
Initial hack at mime document encoding.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13903 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
91eb66c37a
commit
6c640c721f
2 changed files with 276 additions and 16 deletions
|
@ -110,6 +110,7 @@
|
||||||
- (GSMimeHeader*) headerNamed: (NSString*)name;
|
- (GSMimeHeader*) headerNamed: (NSString*)name;
|
||||||
- (NSArray*) headersNamed: (NSString*)name;
|
- (NSArray*) headersNamed: (NSString*)name;
|
||||||
- (GSMimeHeader*) makeContentID;
|
- (GSMimeHeader*) makeContentID;
|
||||||
|
- (NSMutableData*) rawMimeData;
|
||||||
- (void) setContent: (id)newContent;
|
- (void) setContent: (id)newContent;
|
||||||
- (void) setContent: (id)newContent
|
- (void) setContent: (id)newContent
|
||||||
type: (NSString*)type
|
type: (NSString*)type
|
||||||
|
|
|
@ -224,13 +224,15 @@ parseCharacterSet(NSString *token)
|
||||||
if ([token isEqualToString: @"iso-8859-1"] == YES)
|
if ([token isEqualToString: @"iso-8859-1"] == YES)
|
||||||
return NSISOLatin1StringEncoding;
|
return NSISOLatin1StringEncoding;
|
||||||
if ([token isEqualToString: @"utf-8"] == YES)
|
if ([token isEqualToString: @"utf-8"] == YES)
|
||||||
return NSISOLatin1StringEncoding;
|
return NSUTF8StringEncoding;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now try all remaining character sets in alphabetical order.
|
* Now try all remaining character sets in alphabetical order.
|
||||||
*/
|
*/
|
||||||
if ([token isEqualToString: @"ascii"] == YES)
|
if ([token isEqualToString: @"ascii"] == YES)
|
||||||
return NSASCIIStringEncoding;
|
return NSASCIIStringEncoding;
|
||||||
|
if ([token isEqualToString: @"iso-8859-2"] == YES)
|
||||||
|
return NSISOLatin2StringEncoding;
|
||||||
if ([token isEqualToString: @"iso-8859-3"] == YES)
|
if ([token isEqualToString: @"iso-8859-3"] == YES)
|
||||||
return NSISOLatin3StringEncoding;
|
return NSISOLatin3StringEncoding;
|
||||||
if ([token isEqualToString: @"iso-8859-4"] == YES)
|
if ([token isEqualToString: @"iso-8859-4"] == YES)
|
||||||
|
@ -267,6 +269,57 @@ parseCharacterSet(NSString *token)
|
||||||
return NSASCIIStringEncoding; // Default character set.
|
return NSASCIIStringEncoding; // Default character set.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NSString *
|
||||||
|
selectCharacterSet(NSString *str, NSData **d)
|
||||||
|
{
|
||||||
|
if ([str length] == 0)
|
||||||
|
{
|
||||||
|
*d = [NSData data];
|
||||||
|
return @"us-ascii"; // Default character set.
|
||||||
|
}
|
||||||
|
if ((*d = [str dataUsingEncoding: NSASCIIStringEncoding]) != nil)
|
||||||
|
return @"us-ascii"; // Default character set.
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin1StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-1";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin2StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-2";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin3StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-3";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin4StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-4";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOCyrillicStringEncoding]) != nil)
|
||||||
|
return @"iso-8859-5";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOArabicStringEncoding]) != nil)
|
||||||
|
return @"iso-8859-6";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOGreekStringEncoding]) != nil)
|
||||||
|
return @"iso-8859-7";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOHebrewStringEncoding]) != nil)
|
||||||
|
return @"iso-8859-8";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin5StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-9";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin6StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-10";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin7StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-13";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin8StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-14";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSISOLatin9StringEncoding]) != nil)
|
||||||
|
return @"iso-8859-15";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSWindowsCP1250StringEncoding]) != nil)
|
||||||
|
return @"windows-1250";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSWindowsCP1251StringEncoding]) != nil)
|
||||||
|
return @"windows-1251";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSWindowsCP1252StringEncoding]) != nil)
|
||||||
|
return @"windows-1252";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSWindowsCP1253StringEncoding]) != nil)
|
||||||
|
return @"windows-1253";
|
||||||
|
if ((*d = [str dataUsingEncoding: NSWindowsCP1254StringEncoding]) != nil)
|
||||||
|
return @"windows-1254";
|
||||||
|
|
||||||
|
*d = [str dataUsingEncoding: NSUTF8StringEncoding];
|
||||||
|
return @"utf-8"; // Catch-all character set.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The most rudimentary context ... this is used for decoding plain
|
* The most rudimentary context ... this is used for decoding plain
|
||||||
* text and binary dat (ie data which is not really decoded at all)
|
* text and binary dat (ie data which is not really decoded at all)
|
||||||
|
@ -2625,9 +2678,19 @@ static NSCharacterSet *tokenSet = nil;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
|
|
||||||
[t appendString: [[self name] capitalizedString]];
|
[t appendString: [[self name] capitalizedString]];
|
||||||
[t appendString: @": "];
|
if ([t length] + [value length] + 2 > 72)
|
||||||
[t appendString: value];
|
{
|
||||||
l = [t length];
|
[t appendString: @":\r\n\t"];
|
||||||
|
[t appendString: value];
|
||||||
|
l = [t length] + 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[t appendString: @": "];
|
||||||
|
[t appendString: value];
|
||||||
|
l = [t length];
|
||||||
|
}
|
||||||
|
|
||||||
while ((k = [e nextObject]) != nil)
|
while ((k = [e nextObject]) != nil)
|
||||||
{
|
{
|
||||||
NSString *v = [GSMimeHeader makeQuoted: [params objectForKey: k]];
|
NSString *v = [GSMimeHeader makeQuoted: [params objectForKey: k]];
|
||||||
|
@ -2636,11 +2699,14 @@ static NSCharacterSet *tokenSet = nil;
|
||||||
|
|
||||||
if ((l + kl + vl + 3) > 72)
|
if ((l + kl + vl + 3) > 72)
|
||||||
{
|
{
|
||||||
[t appendString: @"\r\n\t"];
|
[t appendFormat: @";\r\n\t%@=%@", k, v];
|
||||||
l = 8;
|
l = kl + vl + 9;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[t appendFormat: @"; %@=%@", k, v];
|
||||||
|
l += kl + vl + 3;
|
||||||
}
|
}
|
||||||
[t appendFormat: @"; %@=%@", k, v];
|
|
||||||
l += kl + vl + 3;
|
|
||||||
}
|
}
|
||||||
[t appendString: @"\r\n"];
|
[t appendString: @"\r\n"];
|
||||||
|
|
||||||
|
@ -3120,7 +3186,10 @@ static NSCharacterSet *tokenSet = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the content as an NSData object (unless it is multipart)
|
* Return the content as an NSData object (unless it is multipart)<br />
|
||||||
|
* Perform conversion from text to data using the charset specified in
|
||||||
|
* the content-type header, or infer the charset, and update the header
|
||||||
|
* accordingly.
|
||||||
*/
|
*/
|
||||||
- (NSData*) convertToData
|
- (NSData*) convertToData
|
||||||
{
|
{
|
||||||
|
@ -3130,9 +3199,18 @@ static NSCharacterSet *tokenSet = nil;
|
||||||
{
|
{
|
||||||
GSMimeHeader *hdr = [self headerNamed: @"content-type"];
|
GSMimeHeader *hdr = [self headerNamed: @"content-type"];
|
||||||
NSString *charset = [hdr parameterForKey: @"charset"];
|
NSString *charset = [hdr parameterForKey: @"charset"];
|
||||||
NSStringEncoding enc = parseCharacterSet(charset);
|
|
||||||
|
|
||||||
d = [content dataUsingEncoding: enc];
|
if (charset != nil)
|
||||||
|
{
|
||||||
|
NSStringEncoding enc = parseCharacterSet(charset);
|
||||||
|
|
||||||
|
d = [content dataUsingEncoding: enc];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
charset = selectCharacterSet(content, &d);
|
||||||
|
[hdr setParameter: charset forKey: @"charset"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ([content isKindOfClass: [NSData class]] == YES)
|
else if ([content isKindOfClass: [NSData class]] == YES)
|
||||||
{
|
{
|
||||||
|
@ -3288,6 +3366,178 @@ static NSCharacterSet *tokenSet = nil;
|
||||||
return hdr;
|
return hdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an NSData object representing the MIME document as raw data
|
||||||
|
* ready to be sent via an email system.
|
||||||
|
*/
|
||||||
|
- (NSMutableData*) rawMimeData
|
||||||
|
{
|
||||||
|
NSData *d = nil;
|
||||||
|
NSMutableData *md;
|
||||||
|
NSEnumerator *enumerator;
|
||||||
|
GSMimeHeader *type;
|
||||||
|
GSMimeHeader *enc;
|
||||||
|
GSMimeHeader *hdr;
|
||||||
|
NSData *boundary;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure there is a mime version header.
|
||||||
|
*/
|
||||||
|
hdr = [self headerNamed: @"mime-version"];
|
||||||
|
if (hdr == nil)
|
||||||
|
{
|
||||||
|
hdr = [GSMimeHeader alloc];
|
||||||
|
hdr = [hdr initWithName: @"mime-version" value: @"1.0" parameters: nil];
|
||||||
|
[self addHeader: hdr];
|
||||||
|
RELEASE(hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
type = [self headerNamed: @"content-type"];
|
||||||
|
if (type == nil)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Attempt to infer the content type from the content.
|
||||||
|
*/
|
||||||
|
if ([content isKindOfClass: [NSString class]] == YES)
|
||||||
|
{
|
||||||
|
[self setContent: content
|
||||||
|
type: @"text"
|
||||||
|
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"
|
||||||
|
name: nil];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"[%@ -%@:] with bad content",
|
||||||
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||||
|
}
|
||||||
|
type = [self headerNamed: @"content-type"];
|
||||||
|
}
|
||||||
|
enc = [self headerNamed: @"content-transfer-encoding"];
|
||||||
|
if ([[type parameterForKey: @"type"] isEqual: @"multipart"] == YES)
|
||||||
|
{
|
||||||
|
NSString *v;
|
||||||
|
|
||||||
|
if (enc != nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"[%@ -%@:] content transfer encoding not supported",
|
||||||
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||||
|
}
|
||||||
|
v = [type parameterForKey: @"boundary"];
|
||||||
|
if (v == nil)
|
||||||
|
{
|
||||||
|
v = makeUniqueString();
|
||||||
|
[type setParameter: v forKey: @"boundary"];
|
||||||
|
}
|
||||||
|
boundary = [v dataUsingEncoding: NSASCIIStringEncoding];
|
||||||
|
}
|
||||||
|
else if (enc == nil)
|
||||||
|
{
|
||||||
|
enc = [GSMimeHeader alloc];
|
||||||
|
if ([[type parameterForKey: @"type"] isEqual: @"text"] == YES)
|
||||||
|
{
|
||||||
|
enc = [enc initWithName: @"content-transfer-encoding"
|
||||||
|
value: @"8bit"
|
||||||
|
parameters: nil];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enc = [enc initWithName: @"content-transfer-encoding"
|
||||||
|
value: @"base64"
|
||||||
|
parameters: nil];
|
||||||
|
}
|
||||||
|
[self addHeader: enc];
|
||||||
|
RELEASE(enc);
|
||||||
|
d = [self convertToData];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now build the output.
|
||||||
|
*/
|
||||||
|
md = [NSMutableData dataWithCapacity: 1024];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add all the headers.
|
||||||
|
*/
|
||||||
|
enumerator = [headers objectEnumerator];
|
||||||
|
while ((hdr = [enumerator nextObject]) != nil)
|
||||||
|
{
|
||||||
|
[md appendData: [[hdr text] dataUsingEncoding: NSASCIIStringEncoding]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Separate headers from body.
|
||||||
|
*/
|
||||||
|
[md appendBytes: "\r\n" length: 2];
|
||||||
|
|
||||||
|
if (enc == nil)
|
||||||
|
{
|
||||||
|
unsigned count;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For a multipart document, insert the boundary between each part.
|
||||||
|
*/
|
||||||
|
[md appendBytes: "--" length: 2];
|
||||||
|
[md appendData: boundary];
|
||||||
|
[md appendBytes: "\r\n" length: 2];
|
||||||
|
count = [content count];
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
CREATE_AUTORELEASE_POOL(arp);
|
||||||
|
NSMutableData *part = [[content objectAtIndex: i] rawMimeData];
|
||||||
|
|
||||||
|
[md appendData: part];
|
||||||
|
[md appendBytes: "\r\n--" length: 2];
|
||||||
|
[md appendData: boundary];
|
||||||
|
[md appendBytes: "\r\n" length: 2];
|
||||||
|
RELEASE(arp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ([[enc value] isEqual: @"base64"] == YES)
|
||||||
|
{
|
||||||
|
const char *ptr;
|
||||||
|
unsigned len;
|
||||||
|
unsigned pos = 0;
|
||||||
|
|
||||||
|
d = [GSMimeDocument encodeBase64: d];
|
||||||
|
ptr = [d bytes];
|
||||||
|
len = [d length];
|
||||||
|
|
||||||
|
while (len - pos > 76)
|
||||||
|
{
|
||||||
|
[md appendBytes: &ptr[pos] length: 76];
|
||||||
|
[md appendBytes: "\r\n" length: 2];
|
||||||
|
pos += 76;
|
||||||
|
}
|
||||||
|
[md appendBytes: &ptr[pos] length: len-pos];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[md appendData: d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new value for the content of the document.
|
* Sets a new value for the content of the document.
|
||||||
*/
|
*/
|
||||||
|
@ -3295,17 +3545,26 @@ static NSCharacterSet *tokenSet = nil;
|
||||||
{
|
{
|
||||||
if ([newContent isKindOfClass: [NSString class]] == YES)
|
if ([newContent isKindOfClass: [NSString class]] == YES)
|
||||||
{
|
{
|
||||||
ASSIGNCOPY(content, newContent);
|
if (newContent != content)
|
||||||
|
{
|
||||||
|
ASSIGNCOPY(content, newContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ([newContent isKindOfClass: [NSData class]] == YES)
|
else if ([newContent isKindOfClass: [NSData class]] == YES)
|
||||||
{
|
{
|
||||||
ASSIGNCOPY(content, newContent);
|
if (newContent != content)
|
||||||
|
{
|
||||||
|
ASSIGNCOPY(content, newContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ([newContent isKindOfClass: [NSArray class]] == YES)
|
else if ([newContent isKindOfClass: [NSArray class]] == YES)
|
||||||
{
|
{
|
||||||
newContent = [newContent mutableCopy];
|
if (newContent != content)
|
||||||
ASSIGN(content, newContent);
|
{
|
||||||
RELEASE(newContent);
|
newContent = [newContent mutableCopy];
|
||||||
|
ASSIGN(content, newContent);
|
||||||
|
RELEASE(newContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue