Some Mime improvements.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13725 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2002-05-27 16:59:43 +00:00
parent f2ba0022d6
commit 82c725d5c5
2 changed files with 382 additions and 17 deletions

View file

@ -3,7 +3,9 @@
* Headers/Foundation/GSMime.h: Tidy up and add convenience methods.
* Source/Additions/GSMime.m: Tidy up and add convenience methods.
Added methods to convert content between string and data for ease
of use from java.
of use from java. Added support for most character sets handled
by GNUstep-base. Improved ContentID generation to be both unlikely
to recur, and to be guaranteed unique within a process.
* Source/NSBundle.m: ([+allBundles]) Don't enumeraste if map table
has not been created yet.
* Source/NSLog.m: Allow output descriptor to be changed.

View file

@ -43,11 +43,6 @@
that permits overriding in order to extend the functionality to
cope with new document types.
</desc>
<term>unparser</term>
<desc>
An object to take a mime/http document and produce a data object
suitable for transmission.
</desc>
</deflist>
</chapter>
$Date$ $Revision$
@ -60,6 +55,8 @@
static unsigned _count = 0;
static NSString *makeUniqueString();
static NSCharacterSet *specials = nil;
/*
@ -207,12 +204,62 @@ decodeWord(unsigned char *dst, unsigned char *src, unsigned char *end, WE enc)
static NSStringEncoding
parseCharacterSet(NSString *token)
{
if ([token compare: @"us-ascii"] == NSOrderedSame)
if (token == nil)
{
return NSASCIIStringEncoding; // Default character set.
}
token = [token lowercaseString];
/*
* Try the three most popular charactersets first - for efficiency.
*/
if ([token isEqualToString: @"us-ascii"] == YES)
return NSASCIIStringEncoding;
if ([token compare: @"iso-8859-1"] == NSOrderedSame)
if ([token isEqualToString: @"iso-8859-1"] == YES)
return NSISOLatin1StringEncoding;
if ([token isEqualToString: @"utf-8"] == YES)
return NSISOLatin1StringEncoding;
return NSASCIIStringEncoding;
/*
* Now try all remaining character sets in alphabetical order.
*/
if ([token isEqualToString: @"ascii"] == YES)
return NSASCIIStringEncoding;
if ([token isEqualToString: @"iso-8859-3"] == YES)
return NSISOLatin3StringEncoding;
if ([token isEqualToString: @"iso-8859-4"] == YES)
return NSISOLatin4StringEncoding;
if ([token isEqualToString: @"iso-8859-5"] == YES)
return NSISOCyrillicStringEncoding;
if ([token isEqualToString: @"iso-8859-6"] == YES)
return NSISOArabicStringEncoding;
if ([token isEqualToString: @"iso-8859-7"] == YES)
return NSISOGreekStringEncoding;
if ([token isEqualToString: @"iso-8859-8"] == YES)
return NSISOHebrewStringEncoding;
if ([token isEqualToString: @"iso-8859-9"] == YES)
return NSISOLatin5StringEncoding;
if ([token isEqualToString: @"iso-8859-10"] == YES)
return NSISOLatin6StringEncoding;
if ([token isEqualToString: @"iso-8859-13"] == YES)
return NSISOLatin7StringEncoding;
if ([token isEqualToString: @"iso-8859-14"] == YES)
return NSISOLatin8StringEncoding;
if ([token isEqualToString: @"iso-8859-15"] == YES)
return NSISOLatin9StringEncoding;
if ([token isEqualToString: @"windows-1250"] == YES)
return NSWindowsCP1250StringEncoding;
if ([token isEqualToString: @"windows-1251"] == YES)
return NSWindowsCP1251StringEncoding;
if ([token isEqualToString: @"windows-1252"] == YES)
return NSWindowsCP1252StringEncoding;
if ([token isEqualToString: @"windows-1253"] == YES)
return NSWindowsCP1253StringEncoding;
if ([token isEqualToString: @"windows-1254"] == YES)
return NSWindowsCP1254StringEncoding;
return NSASCIIStringEncoding; // Default character set.
}
/**
@ -1973,7 +2020,6 @@ parseCharacterSet(NSString *token)
if ([type isEqualToString: @"text"] == YES)
{
NSDictionary *params;
NSString *charset;
NSStringEncoding stringEncoding;
NSString *string;
@ -1981,8 +2027,7 @@ parseCharacterSet(NSString *token)
/*
* Assume that content type is best represented as NSString.
*/
params = [typeInfo objectForKey: @"Parameters"];
charset = [params objectForKey: @"charset"];
charset = [typeInfo parameterForKey: @"charset"];
stringEncoding = parseCharacterSet(charset);
string = [[NSString alloc] initWithData: data
encoding: stringEncoding];
@ -2795,7 +2840,9 @@ static NSCharacterSet *tokenSet = nil;
if ([content isKindOfClass: [NSString class]] == YES)
{
NSStringEncoding enc = NSUTF8StringEncoding;
GSMimeHeader *hdr = [self headerNamed: @"content-type"];
NSString *charset = [hdr parameterForKey: @"charset"];
NSStringEncoding enc = parseCharacterSet(charset);
d = [content dataUsingEncoding: enc];
}
@ -2819,7 +2866,9 @@ static NSCharacterSet *tokenSet = nil;
}
else if ([content isKindOfClass: [NSData class]] == YES)
{
NSStringEncoding enc = NSUTF8StringEncoding;
GSMimeHeader *hdr = [self headerNamed: @"content-type"];
NSString *charset = [hdr parameterForKey: @"charset"];
NSStringEncoding enc = parseCharacterSet(charset);
s = [[NSString alloc] initWithData: content encoding: enc];
AUTORELEASE(s);
@ -2941,12 +2990,10 @@ static NSCharacterSet *tokenSet = nil;
*/
- (GSMimeHeader*) makeContentID
{
NSString *val;
GSMimeHeader *hdr;
val = [NSString stringWithFormat: @"GSMime%08x%08x", self, _count++];
hdr = [[GSMimeHeader alloc] initWithName: @"content-id"
value: val
value: makeUniqueString()
parameters: nil];
[self setHeader: hdr];
RELEASE(hdr);
@ -3050,3 +3097,319 @@ static NSCharacterSet *tokenSet = nil;
@end
#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
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include <string.h> /* for memcpy() */
/*
* Ensure data is little-endian
*/
static void littleEndian (void *buf, unsigned longs)
{
unsigned long *ptr = (unsigned long*)buf;
do
{
*ptr = NSSwapHostLongToLittle(*ptr);
ptr++;
}
while (--longs);
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init (struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static void MD5Update (struct MD5Context *ctx, unsigned char const *buf,
unsigned len)
{
unsigned long t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((unsigned long) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t)
{
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t)
{
memcpy (p, buf, len);
return;
}
memcpy (p, buf, t);
littleEndian (ctx->in, 16);
MD5Transform (ctx->buf, (unsigned long *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64)
{
memcpy (ctx->in, buf, 64);
littleEndian (ctx->in, 16);
MD5Transform (ctx->buf, (unsigned long *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy (ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
static void MD5Final (unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8)
{
/* Two lots of padding: Pad the first block to 64 bytes */
memset (p, 0, count);
littleEndian (ctx->in, 16);
MD5Transform (ctx->buf, (unsigned long *) ctx->in);
/* Now fill the next block with 56 bytes */
memset (ctx->in, 0, 56);
}
else
{
/* Pad block to 56 bytes */
memset (p, 0, count - 8);
}
littleEndian (ctx->in, 14);
/* Append length in bits and transform */
((unsigned long *) ctx->in)[14] = ctx->bits[0];
((unsigned long *) ctx->in)[15] = ctx->bits[1];
MD5Transform (ctx->buf, (unsigned long *) ctx->in);
littleEndian ((unsigned char *) ctx->buf, 4);
memcpy (digest, ctx->buf, 16);
memset (ctx, 0, sizeof (ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform (unsigned long buf[4], unsigned long const in[16])
{
register unsigned long a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP (F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP (F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP (F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP (F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP (F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP (F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP (F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP (F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP (F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP (F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP (F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP (F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP (F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP (F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP (F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP (F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP (F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP (F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP (F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP (F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP (F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP (F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP (F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP (F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP (F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP (F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP (F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP (F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP (F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP (F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP (F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP (F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP (F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP (F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP (F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP (F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP (F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP (F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP (F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP (F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP (F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP (F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP (F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP (F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP (F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP (F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP (F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP (F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP (F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP (F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP (F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP (F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP (F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*
* Make a probably unique string of 40 hexadecimal digits
* consisting of an MD5 digest of soe 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 hex[4];
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;
for (i = 0; i < 20; i++)
{
int v;
v = (digest[i] >> 4) & 0xf;
if (v > 9)
{
hex[i*2] = 'A' + v - 10;
}
else
{
hex[i*2] = '0' + v;
}
v = digest[i] & 0xf;
if (v > 9)
{
hex[i*2 + 1] = 'A' + v - 10;
}
else
{
hex[i*2 + 1] = '0' + v;
}
}
return [NSString stringWithCString: hex length: 40];
}