mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 08:26:27 +00:00
Mime parsing updates.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13701 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
9a059a2d2f
commit
a04176e391
5 changed files with 297 additions and 269 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
* Headers/Foundation/GSMime.h: Add GSMimeHeader class.
|
||||
* Source/Additions/GSMime.m: Add GSMimeHeader class.
|
||||
Update API to use GSMimeheaders rather than dictionaries.
|
||||
|
||||
2002-05-23 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
|
|
|
@ -57,16 +57,22 @@
|
|||
{
|
||||
NSString *name;
|
||||
NSString *value;
|
||||
NSMutableDictionary *objects;
|
||||
NSMutableDictionary *params;
|
||||
}
|
||||
- (id) initWithName: (NSString*)n value: (NSString*)v params: (NSDictionary*)p;
|
||||
- (NSString*) makeQuoted: (NSString*)v;
|
||||
- (NSString*) makeToken: (NSString*)t;
|
||||
+ (NSString*) makeQuoted: (NSString*)v;
|
||||
+ (NSString*) makeToken: (NSString*)t;
|
||||
- (id) initWithName: (NSString*)n
|
||||
value: (NSString*)v
|
||||
parameters: (NSDictionary*)p;
|
||||
- (NSString*) name;
|
||||
- (NSDictionary*) params;
|
||||
- (id) objectForKey: (NSString*)k;
|
||||
- (NSString*) parameterForKey: (NSString*)k;
|
||||
- (NSDictionary*) parameters;
|
||||
- (void) setName: (NSString*)s;
|
||||
- (void) setParam: (NSString*)v forKey: (NSString*)k;
|
||||
- (void) setParams: (NSDictionary*)d;
|
||||
- (void) setObject: (id)o forKey: (NSString*)k;
|
||||
- (void) setParameter: (NSString*)v forKey: (NSString*)k;
|
||||
- (void) setParameters: (NSDictionary*)d;
|
||||
- (void) setValue: (NSString*)s;
|
||||
- (NSString*) text;
|
||||
- (NSString*) value;
|
||||
|
@ -81,15 +87,16 @@
|
|||
|
||||
+ (GSMimeDocument*) mimeDocument;
|
||||
|
||||
- (BOOL) addHeader: (NSDictionary*)info;
|
||||
- (BOOL) addContent: (id)newContent;
|
||||
- (BOOL) addHeader: (GSMimeHeader*)info;
|
||||
- (NSArray*) allHeaders;
|
||||
- (id) content;
|
||||
- (void) deleteHeader: (NSString*)aHeader;
|
||||
- (void) deleteHeader: (GSMimeHeader*)aHeader;
|
||||
- (void) deleteHeaderNamed: (NSString*)name;
|
||||
- (NSDictionary*) headerNamed: (NSString*)name;
|
||||
- (GSMimeHeader*) headerNamed: (NSString*)name;
|
||||
- (NSArray*) headersNamed: (NSString*)name;
|
||||
- (BOOL) setContent: (id)newContent;
|
||||
- (BOOL) setHeader: (NSDictionary*)info;
|
||||
- (BOOL) setHeader: (GSMimeHeader*)info;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -114,7 +121,7 @@
|
|||
|
||||
+ (GSMimeParser*) mimeParser;
|
||||
|
||||
- (GSMimeCodingContext*) contextFor: (NSDictionary*)info;
|
||||
- (GSMimeCodingContext*) contextFor: (GSMimeHeader*)info;
|
||||
- (NSData*) data;
|
||||
- (BOOL) decodeData: (NSData*)sData
|
||||
fromRange: (NSRange)aRange
|
||||
|
@ -126,13 +133,11 @@
|
|||
- (BOOL) isInHeaders;
|
||||
- (BOOL) parse: (NSData*)d;
|
||||
- (BOOL) parseHeader: (NSString*)aHeader;
|
||||
- (BOOL) parsedHeaders;
|
||||
- (BOOL) scanHeader: (NSScanner*)scanner
|
||||
named: (NSString*)name
|
||||
into: (NSMutableDictionary*)info;
|
||||
- (BOOL) scanHeaderBody: (NSScanner*)scanner into: (GSMimeHeader*)info;
|
||||
- (BOOL) scanPastSpace: (NSScanner*)scanner;
|
||||
- (NSString*) scanSpecial: (NSScanner*)scanner;
|
||||
- (NSString*) scanToken: (NSScanner*)scanner;
|
||||
- (void) setNoHeaders;
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -108,27 +108,27 @@
|
|||
|
||||
- (NSDictionary*) attributes;
|
||||
- (NSString*) content;
|
||||
- (GSXMLDocument*) document;
|
||||
- (GSXMLAttribute*) firstAttribute;
|
||||
- (GSXMLNode*) firstChild;
|
||||
- (GSXMLNode*) firstChildElement;
|
||||
- (GSXMLDocument*) document;
|
||||
- (void*) lib;
|
||||
- (GSXMLAttribute*) makeAttributeWithName: (NSString*)name
|
||||
value: (NSString*)value;
|
||||
- (GSXMLNode*) makeChildWithNamespace: (GSXMLNamespace*)ns
|
||||
name: (NSString*)name
|
||||
content: (NSString*)content;
|
||||
- (GSXMLNode*) makeComment: (NSString*)content;
|
||||
- (GSXMLNamespace*) makeNamespaceHref: (NSString*)href
|
||||
prefix: (NSString*)prefix;
|
||||
- (GSXMLNode*) makeText: (NSString*)content;
|
||||
- (GSXMLNode*) makeComment: (NSString*)content;
|
||||
- (GSXMLNode*) makePI: (NSString*)name
|
||||
content: (NSString*)content;
|
||||
- (GSXMLNode*) makeText: (NSString*)content;
|
||||
- (NSString*) name;
|
||||
- (GSXMLNode*) next;
|
||||
- (GSXMLNode*) nextElement;
|
||||
- (GSXMLNamespace*) namespace;
|
||||
- (GSXMLNamespace*) namespaceDefinitions;
|
||||
- (GSXMLNode*) next;
|
||||
- (GSXMLNode*) nextElement;
|
||||
- (NSString*) objectForKey: (NSString*)key;
|
||||
- (GSXMLNode*) parent;
|
||||
- (GSXMLNode*) previous;
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static unsigned _count = 0;
|
||||
|
||||
static NSCharacterSet *specials = nil;
|
||||
|
||||
/*
|
||||
|
@ -352,7 +354,7 @@ parseCharacterSet(NSString *token)
|
|||
* <item>chunked (for HTTP/1.1)</item>
|
||||
* </list>
|
||||
*/
|
||||
- (GSMimeCodingContext*) contextFor: (NSDictionary*)info
|
||||
- (GSMimeCodingContext*) contextFor: (GSMimeHeader*)info
|
||||
{
|
||||
NSString *name;
|
||||
NSString *value;
|
||||
|
@ -362,11 +364,11 @@ parseCharacterSet(NSString *token)
|
|||
return AUTORELEASE([GSMimeCodingContext new]);
|
||||
}
|
||||
|
||||
name = [info objectForKey: @"Name"];
|
||||
name = [info name];
|
||||
if ([name isEqualToString: @"content-transfer-encoding"] == YES
|
||||
|| [name isEqualToString: @"transfer-encoding"] == YES)
|
||||
{
|
||||
value = [info objectForKey: @"Value"];
|
||||
value = [[info value] lowercaseString];
|
||||
if ([value length] == 0)
|
||||
{
|
||||
NSLog(@"Bad value for %@ header - assume binary encoding", name);
|
||||
|
@ -1031,25 +1033,25 @@ parseCharacterSet(NSString *token)
|
|||
/**
|
||||
* <p>
|
||||
* This method is called to parse a header line <em>for the
|
||||
* current document</em>, split its contents into an info
|
||||
* dictionary, and add that information to the document.
|
||||
* current document</em>, split its contents into a GSMimeHeader
|
||||
* object, and add that information to the document.
|
||||
* </p>
|
||||
* <p>
|
||||
* The standard implementation of this method scans basic
|
||||
* information and then calls -scanHeader:named:into:
|
||||
* to complete the parsing of the header.
|
||||
* The standard implementation of this method scans the header
|
||||
* name and then calls -scanHeaderBody:into: to complete the
|
||||
* parsing of the header.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method also performs consistency checks on headers scanned
|
||||
* so it is recommended that it is not overridden, but that
|
||||
* subclasses override -scanHeader:named:into: to
|
||||
* subclasses override -scanHeaderBody:into: to
|
||||
* implement custom scanning.
|
||||
* </p>
|
||||
* <p>
|
||||
* As a special case, for HTTP support, this method also parses
|
||||
* lines in the format of HTTP responses as if they were headers
|
||||
* named <code>http</code>. The resulting header info dictionary
|
||||
* contains -
|
||||
* named <code>http</code>. The resulting header object contains
|
||||
* additional object values -
|
||||
* </p>
|
||||
* <deflist>
|
||||
* <term>HttpMajorVersion</term>
|
||||
|
@ -1069,16 +1071,10 @@ parseCharacterSet(NSString *token)
|
|||
NSScanner *scanner = [NSScanner scannerWithString: aHeader];
|
||||
NSString *name;
|
||||
NSString *value;
|
||||
NSMutableDictionary *info;
|
||||
GSMimeHeader *info;
|
||||
NSCharacterSet *skip;
|
||||
unsigned count;
|
||||
|
||||
info = [NSMutableDictionary dictionary];
|
||||
|
||||
/*
|
||||
* Store the raw header string in the info dictionary.
|
||||
*/
|
||||
[info setObject: [scanner string] forKey: @"RawHeader"];
|
||||
info = AUTORELEASE([GSMimeHeader new]);
|
||||
|
||||
/*
|
||||
* Special case - permit web response status line to act like a header.
|
||||
|
@ -1102,29 +1098,21 @@ parseCharacterSet(NSString *token)
|
|||
}
|
||||
|
||||
/*
|
||||
* Store the Raw header name and a lowercase version too.
|
||||
* Set the header name.
|
||||
*/
|
||||
name = [name stringByTrimmingTailSpaces];
|
||||
[info setObject: name forKey: @"BaseName"];
|
||||
name = [name lowercaseString];
|
||||
[info setObject: name forKey: @"Name"];
|
||||
|
||||
[info setName: name];
|
||||
name = [info name];
|
||||
|
||||
skip = RETAIN([scanner charactersToBeSkipped]);
|
||||
[scanner setCharactersToBeSkipped: nil];
|
||||
[scanner scanCharactersFromSet: skip intoString: 0];
|
||||
[scanner setCharactersToBeSkipped: skip];
|
||||
RELEASE(skip);
|
||||
|
||||
/*
|
||||
* Set remainder of header as a base value.
|
||||
*/
|
||||
[info setObject: [[scanner string] substringFromIndex: [scanner scanLocation]]
|
||||
forKey: @"BaseValue"];
|
||||
|
||||
/*
|
||||
* Break header fields out into info dictionary.
|
||||
*/
|
||||
if ([self scanHeader: scanner named: name into: info] == NO)
|
||||
if ([self scanHeaderBody: scanner into: info] == NO)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
@ -1137,7 +1125,7 @@ parseCharacterSet(NSString *token)
|
|||
int majv = 0;
|
||||
int minv = 0;
|
||||
|
||||
value = [info objectForKey: @"BaseValue"];
|
||||
value = [info value];
|
||||
if ([value length] == 0)
|
||||
{
|
||||
NSLog(@"Missing value for mime-version header");
|
||||
|
@ -1177,8 +1165,7 @@ parseCharacterSet(NSString *token)
|
|||
}
|
||||
else if ([type isEqualToString: @"multipart"] == YES)
|
||||
{
|
||||
NSDictionary *par = [info objectForKey: @"Parameters"];
|
||||
NSString *tmp = [par objectForKey: @"boundary"];
|
||||
NSString *tmp = [info parameterForKey: @"boundary"];
|
||||
|
||||
supported = YES;
|
||||
if (tmp != nil)
|
||||
|
@ -1201,46 +1188,9 @@ parseCharacterSet(NSString *token)
|
|||
[document deleteHeaderNamed: name]; // Should be unique
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that info dictionary is immutable by making a copy
|
||||
* of all keys and objects and placing them in a new dictionary.
|
||||
*/
|
||||
count = [info count];
|
||||
{
|
||||
id keys[count];
|
||||
id objects[count];
|
||||
unsigned index;
|
||||
|
||||
[[info allKeys] getObjects: keys];
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
keys[index] = [keys[index] copy];
|
||||
objects[index] = [[info objectForKey: keys[index]] copy];
|
||||
}
|
||||
info = [NSDictionary dictionaryWithObjects: objects
|
||||
forKeys: keys
|
||||
count: count];
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
RELEASE(objects[index]);
|
||||
RELEASE(keys[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return [document addHeader: info];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns YES if the parser is expecting to read mime headers,
|
||||
* Returns NO is the parser has already been passed all the
|
||||
* data containing headers, and is now waiting for the body of
|
||||
* the mime message (or has been passed all data).
|
||||
*/
|
||||
- (BOOL) parsedHeaders
|
||||
{
|
||||
return inBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This method is called to parse a header line and split its
|
||||
|
@ -1270,11 +1220,6 @@ parseCharacterSet(NSString *token)
|
|||
* <term>content-disposition</term>
|
||||
* <desc>
|
||||
* <deflist>
|
||||
* <term>Parameters</term>
|
||||
* <desc>
|
||||
* A dictionary containing parameters as key-value pairs
|
||||
* in lowercase
|
||||
* </desc>
|
||||
* <term>Value</term>
|
||||
* <desc>
|
||||
* The content disposition (excluding parameters) as a
|
||||
|
@ -1285,11 +1230,6 @@ parseCharacterSet(NSString *token)
|
|||
* <term>content-type</term>
|
||||
* <desc>
|
||||
* <deflist>
|
||||
* <term>Parameters</term>
|
||||
* <desc>
|
||||
* A dictionary containing parameters as key-value pairs
|
||||
* in lowercase.
|
||||
* </desc>
|
||||
* <term>SubType</term>
|
||||
* <desc>The MIME subtype lowercase</desc>
|
||||
* <term>Type</term>
|
||||
|
@ -1329,18 +1269,18 @@ parseCharacterSet(NSString *token)
|
|||
* </desc>
|
||||
* </deflist>
|
||||
*/
|
||||
- (BOOL) scanHeader: (NSScanner*)scanner
|
||||
named: (NSString*)name
|
||||
into: (NSMutableDictionary*)info
|
||||
- (BOOL) scanHeaderBody: (NSScanner*)scanner
|
||||
into: (GSMimeHeader*)info
|
||||
{
|
||||
NSString *name = [info name];
|
||||
NSString *value = nil;
|
||||
NSMutableDictionary *parameters = nil;
|
||||
|
||||
/*
|
||||
* Now see if we are interested in any of it.
|
||||
*/
|
||||
if ([name isEqualToString: @"http"] == YES)
|
||||
{
|
||||
int loc = [scanner scanLocation];
|
||||
int major;
|
||||
int minor;
|
||||
int status;
|
||||
|
@ -1379,16 +1319,16 @@ parseCharacterSet(NSString *token)
|
|||
value = [[scanner string] substringFromIndex: [scanner scanLocation]];
|
||||
[info setObject: value
|
||||
forKey: NSHTTPPropertyStatusReasonKey];
|
||||
value = nil;
|
||||
value = [[scanner string] substringFromIndex: loc];
|
||||
/*
|
||||
* Get rid of preceeding headers in case this is a continuation.
|
||||
*/
|
||||
hdrs = [document allHeaders];
|
||||
for (count = 0; count < [hdrs count]; count++)
|
||||
{
|
||||
NSDictionary *h = [hdrs objectAtIndex: count];
|
||||
GSMimeHeader *h = [hdrs objectAtIndex: count];
|
||||
|
||||
[document deleteHeader: [h objectForKey: @"RawHeader"]];
|
||||
[document deleteHeader: h];
|
||||
}
|
||||
}
|
||||
else if ([name isEqualToString: @"content-transfer-encoding"] == YES
|
||||
|
@ -1451,12 +1391,7 @@ parseCharacterSet(NSString *token)
|
|||
{
|
||||
paramValue = @"";
|
||||
}
|
||||
if (parameters == nil)
|
||||
{
|
||||
parameters = [NSMutableDictionary dictionary];
|
||||
}
|
||||
paramName = [paramName lowercaseString];
|
||||
[parameters setObject: paramValue forKey: paramName];
|
||||
[info setParameter: paramValue forKey: paramName];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1504,12 +1439,7 @@ parseCharacterSet(NSString *token)
|
|||
{
|
||||
paramValue = @"";
|
||||
}
|
||||
if (parameters == nil)
|
||||
{
|
||||
parameters = [NSMutableDictionary dictionary];
|
||||
}
|
||||
paramName = [paramName lowercaseString];
|
||||
[parameters setObject: paramValue forKey: paramName];
|
||||
[info setParameter: paramValue forKey: paramName];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1521,12 +1451,9 @@ parseCharacterSet(NSString *token)
|
|||
|
||||
if (value != nil)
|
||||
{
|
||||
[info setObject: value forKey: @"Value"];
|
||||
}
|
||||
if (parameters != nil)
|
||||
{
|
||||
[info setObject: parameters forKey: @"Parameters"];
|
||||
[info setValue: value];
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -1668,6 +1595,23 @@ parseCharacterSet(NSString *token)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method may be called to tell the parser that it should not expect
|
||||
* to parse any headers, and that the data it will receive is body data.<br />
|
||||
* If the parse is already in the body, or is complete, this method has
|
||||
* no effect.<br />
|
||||
* This is for use when some other utility has been used to parse headers,
|
||||
* and you have set the headers of the document owned by the parser
|
||||
* accordingly. You can then use the GSMimeParser to read the body data
|
||||
* into the document.
|
||||
*/
|
||||
- (void) setNoHeaders
|
||||
{
|
||||
if (complete == NO)
|
||||
{
|
||||
inBody = YES;
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSMimeParser (Private)
|
||||
|
@ -1827,7 +1771,7 @@ parseCharacterSet(NSString *token)
|
|||
|
||||
if (context == nil)
|
||||
{
|
||||
NSDictionary *hdr;
|
||||
GSMimeHeader *hdr;
|
||||
|
||||
expect = 0;
|
||||
/*
|
||||
|
@ -1836,7 +1780,7 @@ parseCharacterSet(NSString *token)
|
|||
hdr = [document headerNamed: @"content-length"];
|
||||
if (hdr != nil)
|
||||
{
|
||||
expect = [[hdr objectForKey: @"BaseValue"] intValue];
|
||||
expect = [[hdr value] intValue];
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1847,7 +1791,7 @@ parseCharacterSet(NSString *token)
|
|||
{
|
||||
hdr = [document headerNamed: @"content-transfer-encoding"];
|
||||
}
|
||||
else if ([[hdr objectForKey: @"Value"] isEqual: @"chunked"] == YES)
|
||||
else if ([[[hdr value] lowercaseString] isEqual: @"chunked"] == YES)
|
||||
{
|
||||
/*
|
||||
* Chunked transfer encoding overrides any content length spec.
|
||||
|
@ -1874,7 +1818,7 @@ parseCharacterSet(NSString *token)
|
|||
}
|
||||
else if (boundary == nil)
|
||||
{
|
||||
NSDictionary *typeInfo;
|
||||
GSMimeHeader *typeInfo;
|
||||
NSString *type;
|
||||
|
||||
typeInfo = [document headerNamed: @"content-type"];
|
||||
|
@ -1927,7 +1871,7 @@ parseCharacterSet(NSString *token)
|
|||
* Assume that any non-text content type is best
|
||||
* represented as NSData.
|
||||
*/
|
||||
[document setContent: AUTORELEASE([data copy])];
|
||||
[document setContent: data];
|
||||
}
|
||||
}
|
||||
result = YES;
|
||||
|
@ -2004,26 +1948,26 @@ parseCharacterSet(NSString *token)
|
|||
*/
|
||||
d = [NSData dataWithBytes: &bytes[sectionStart]
|
||||
length: lineStart - sectionStart];
|
||||
if ([child parse: d] == YES || [child parse: nil] == YES)
|
||||
if ([child parse: d] == YES)
|
||||
{
|
||||
/*
|
||||
* The parser wants more data, so pass a nil data item
|
||||
* to tell it that it has had all there is.
|
||||
*/
|
||||
[child parse: nil];
|
||||
}
|
||||
if ([child isComplete] == YES)
|
||||
{
|
||||
NSMutableArray *a;
|
||||
GSMimeDocument *doc;
|
||||
|
||||
/*
|
||||
* Store the document produced by the child, and
|
||||
* create a new parser for the next section.
|
||||
*/
|
||||
a = [document content];
|
||||
if (a == nil)
|
||||
{
|
||||
a = [NSMutableArray new];
|
||||
[document setContent: a];
|
||||
RELEASE(a);
|
||||
}
|
||||
doc = [child document];
|
||||
if (doc != nil)
|
||||
{
|
||||
[a addObject: doc];
|
||||
[document addContent: doc];
|
||||
}
|
||||
RELEASE(child);
|
||||
child = [GSMimeParser new];
|
||||
|
@ -2183,33 +2127,10 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(name);
|
||||
RELEASE(value);
|
||||
RELEASE(params);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
RELEASE(self);
|
||||
NSLog(@"You should initialise GSMime using initWithName:value:params:");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id) initWithName: (NSString*)n value: (NSString*)v params: (NSDictionary*)p
|
||||
{
|
||||
[self setName: n];
|
||||
[self setValue: v];
|
||||
[self setParams: p];
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the value into a quoted string if necessary.
|
||||
*/
|
||||
- (NSString*) makeQuoted: (NSString*)v
|
||||
+ (NSString*) makeQuoted: (NSString*)v
|
||||
{
|
||||
NSRange r;
|
||||
unsigned pos = 0;
|
||||
|
@ -2256,7 +2177,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
* Convert the supplied string to a standardized token by making it
|
||||
* lowercase and removing all illegal characters.
|
||||
*/
|
||||
- (NSString*) makeToken: (NSString*)t
|
||||
+ (NSString*) makeToken: (NSString*)t
|
||||
{
|
||||
NSRange r;
|
||||
|
||||
|
@ -2276,6 +2197,48 @@ static NSCharacterSet *tokenSet = nil;
|
|||
return t;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(name);
|
||||
RELEASE(value);
|
||||
RELEASE(objects);
|
||||
RELEASE(params);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString*) description
|
||||
{
|
||||
NSMutableString *desc;
|
||||
|
||||
desc = [NSMutableString stringWithFormat: @"GSMimeHeader <%0x> -\n", self];
|
||||
[desc appendFormat: @" name: %@\n", [self name]];
|
||||
[desc appendFormat: @" value: %@\n", [self value]];
|
||||
[desc appendFormat: @" params: %@\n", [self parameters]];
|
||||
return desc;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self initWithName: @"unknown" value: @"none" parameters: nil];
|
||||
}
|
||||
|
||||
/**
|
||||
* <init />
|
||||
* Initialise a GSMimeHeader supplying a name, a value and a dictionary
|
||||
* of any parameters occurring after the value.
|
||||
*/
|
||||
- (id) initWithName: (NSString*)n
|
||||
value: (NSString*)v
|
||||
parameters: (NSDictionary*)p
|
||||
{
|
||||
objects = [NSMutableDictionary new];
|
||||
params = [NSMutableDictionary new];
|
||||
[self setName: n];
|
||||
[self setValue: v];
|
||||
[self setParameters: p];
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this header ... a lowercase string.
|
||||
*/
|
||||
|
@ -2284,38 +2247,72 @@ static NSCharacterSet *tokenSet = nil;
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return extra information specific to a particular header type.
|
||||
*/
|
||||
- (id) objectForKey: (NSString*)k
|
||||
{
|
||||
return [objects objectForKey: k];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the named parameter value.
|
||||
*/
|
||||
- (NSString*) parameterForKey: (NSString*)k
|
||||
{
|
||||
NSString *p = [params objectForKey: k];
|
||||
|
||||
if (p == nil)
|
||||
{
|
||||
k = [GSMimeHeader makeToken: k];
|
||||
p = [params objectForKey: k];
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters of this header ... a dictionary whose keys
|
||||
* are all lowercase strings, and whosre value is a string which may
|
||||
* contain mixed case.
|
||||
*/
|
||||
- (NSDictionary*) params
|
||||
- (NSDictionary*) parameters
|
||||
{
|
||||
return AUTORELEASE([params copy]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this header ... converts to lowercase.
|
||||
* Sets the name of this header ... converts to lowercase and removes
|
||||
* illegal characters. If given a nil or empty string argument,
|
||||
* sets the name to 'unknown'.
|
||||
*/
|
||||
- (void) setName: (NSString*)s
|
||||
{
|
||||
s = [self makeToken: s];
|
||||
|
||||
s = [GSMimeHeader makeToken: s];
|
||||
if ([s length] == 0)
|
||||
{
|
||||
s = @"unknown";
|
||||
}
|
||||
ASSIGN(name, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a parameter of this header ... converts name to lowercase.<br />
|
||||
* Method to store specific information for particular types of
|
||||
* header.
|
||||
*/
|
||||
- (void) setObject: (id)o forKey: (NSString*)k
|
||||
{
|
||||
[objects setObject: o forKey: k];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a parameter of this header ... converts name to lowercase and
|
||||
* removes illegal characters.<br />
|
||||
* If a nil parameter name is supplied, removes any parameter with the
|
||||
* specified key.
|
||||
*/
|
||||
- (void) setParam: (NSString*)v forKey: (NSString*)k
|
||||
- (void) setParameter: (NSString*)v forKey: (NSString*)k
|
||||
{
|
||||
if (params == nil)
|
||||
{
|
||||
params = [NSMutableDictionary new];
|
||||
}
|
||||
k = [self makeToken: k];
|
||||
k = [GSMimeHeader makeToken: k];
|
||||
if (v == nil)
|
||||
{
|
||||
[params removeObjectForKey: k];
|
||||
|
@ -2327,9 +2324,10 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets all parameters of this header ... converts names to lowercase.
|
||||
* Sets all parameters of this header ... converts names to lowercase
|
||||
* and removes illegal characters from them.
|
||||
*/
|
||||
- (void) setParams: (NSDictionary*)d
|
||||
- (void) setParameters: (NSDictionary*)d
|
||||
{
|
||||
NSMutableDictionary *m = [NSMutableDictionary new];
|
||||
NSEnumerator *e = [d keyEnumerator];
|
||||
|
@ -2337,23 +2335,28 @@ static NSCharacterSet *tokenSet = nil;
|
|||
|
||||
while ((k = [e nextObject]) != nil)
|
||||
{
|
||||
[m setObject: [d objectForKey: k] forKey: [self makeToken: k]];
|
||||
[m setObject: [d objectForKey: k] forKey: [GSMimeHeader makeToken: k]];
|
||||
}
|
||||
DESTROY(params);
|
||||
params = m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this header (without changing parameters)
|
||||
* Sets the value of this header (without changing parameters)<br />
|
||||
* If given a nil argument, set an empty string value.
|
||||
*/
|
||||
- (void) setValue: (NSString*)s
|
||||
{
|
||||
if (s == nil)
|
||||
{
|
||||
s = @"";
|
||||
}
|
||||
ASSIGN(value, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full text of the header, built from its component parts,
|
||||
* and inclufding a terminating CR-LF
|
||||
* and including a terminating CR-LF
|
||||
*/
|
||||
- (NSString*) text
|
||||
{
|
||||
|
@ -2368,7 +2371,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
l = [t length];
|
||||
while ((k = [e nextObject]) != nil)
|
||||
{
|
||||
NSString *v = [self makeQuoted: [params objectForKey: k]];
|
||||
NSString *v = [GSMimeHeader makeQuoted: [params objectForKey: k]];
|
||||
unsigned kl = [k length];
|
||||
unsigned vl = [v length];
|
||||
|
||||
|
@ -2405,34 +2408,9 @@ static NSCharacterSet *tokenSet = nil;
|
|||
* </p>
|
||||
* <p>
|
||||
* The class keeps track of all the document headers, and provides
|
||||
* methods for modifying the headers that apply to a document and
|
||||
* for looking at the header structures, by providing an info
|
||||
* dictionary containing the various parts of a header.
|
||||
* methods for modifying and examining the headers that apply to a
|
||||
* document.
|
||||
* </p>
|
||||
* <p>
|
||||
* The common dictionary keys used for elements provided for
|
||||
* <em>all</em> headers are -
|
||||
* </p>
|
||||
* <deflist>
|
||||
* <term>RawHeader</term>
|
||||
* <desc>This is the unmodified text of the header
|
||||
* </desc>
|
||||
* <term>BaseName</term>
|
||||
* <desc>This is the header name.
|
||||
* </desc>
|
||||
* <term>BaseValue</term>
|
||||
* <desc>This is the text after the header name and colon.
|
||||
* </desc>
|
||||
* <term>Name</term>
|
||||
* <desc>This is a lowercase representation of the header name.
|
||||
* </desc>
|
||||
* <term>Value</term>
|
||||
* <desc>This is the value of the header (normally lower case).
|
||||
* It may only be a small subset of the information in the header
|
||||
* with other information being split into separate fields
|
||||
* depending on the type of header.
|
||||
* </desc>
|
||||
* </deflist>
|
||||
*/
|
||||
@implementation GSMimeDocument
|
||||
|
||||
|
@ -2463,6 +2441,28 @@ static NSCharacterSet *tokenSet = nil;
|
|||
return AUTORELEASE([[self alloc] init]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a part to a multipart document
|
||||
*/
|
||||
- (BOOL) addContent: (GSMimeDocument*)newContent
|
||||
{
|
||||
BOOL result = YES;
|
||||
|
||||
if (content == nil)
|
||||
{
|
||||
content = [NSMutableArray new];
|
||||
}
|
||||
if ([content isKindOfClass: [NSMutableArray class]] == YES)
|
||||
{
|
||||
[content addObject: newContent];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NO;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This method may be called to add a header to the document.
|
||||
|
@ -2470,25 +2470,22 @@ static NSCharacterSet *tokenSet = nil;
|
|||
* at least the fields that are standard for all headers.
|
||||
* </p>
|
||||
*/
|
||||
- (BOOL) addHeader: (NSDictionary*)info
|
||||
- (BOOL) addHeader: (GSMimeHeader*)info
|
||||
{
|
||||
NSString *name = [info objectForKey: @"Name"];
|
||||
NSString *name = [info name];
|
||||
|
||||
if (name == nil)
|
||||
if (name == nil || [name isEqual: @"unknown"] == YES)
|
||||
{
|
||||
NSLog(@"addHeader: supplied with header info without 'Name' field");
|
||||
NSLog(@"setHeader: supplied with header without valid name");
|
||||
return NO;
|
||||
}
|
||||
|
||||
info = [info copy];
|
||||
[headers addObject: info];
|
||||
RELEASE(info);
|
||||
return YES;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This method returns an array containing NSDictionary objects
|
||||
* This method returns an array containing GSMimeHeader objects
|
||||
* representing the headers associated with the document.
|
||||
* </p>
|
||||
* <p>
|
||||
|
@ -2531,18 +2528,16 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
|
||||
/**
|
||||
* This method removes all occurrances of headers whose raw data
|
||||
* exactly matches the supplied string.
|
||||
* This method removes all occurrances of header objects identical to
|
||||
* the one supplied as an argument.
|
||||
*/
|
||||
- (void) deleteHeader: (NSString*)aHeader
|
||||
- (void) deleteHeader: (GSMimeHeader*)aHeader
|
||||
{
|
||||
unsigned count = [headers count];
|
||||
|
||||
while (count-- > 0)
|
||||
{
|
||||
NSDictionary *info = [headers objectAtIndex: count];
|
||||
|
||||
if ([aHeader isEqualToString: [info objectForKey: @"RawHeader"]] == YES)
|
||||
if ([aHeader isEqual: [headers objectAtIndex: count]] == YES)
|
||||
{
|
||||
[headers removeObjectAtIndex: count];
|
||||
}
|
||||
|
@ -2551,7 +2546,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
|
||||
/**
|
||||
* This method removes all occurrances of headers whose name
|
||||
* exactly matches the supplied string.
|
||||
* matches the supplied string.
|
||||
*/
|
||||
- (void) deleteHeaderNamed: (NSString*)name
|
||||
{
|
||||
|
@ -2560,9 +2555,9 @@ static NSCharacterSet *tokenSet = nil;
|
|||
name = [name lowercaseString];
|
||||
while (count-- > 0)
|
||||
{
|
||||
NSDictionary *info = [headers objectAtIndex: count];
|
||||
GSMimeHeader *info = [headers objectAtIndex: count];
|
||||
|
||||
if ([name isEqualToString: [info objectForKey: @"Name"]] == YES)
|
||||
if ([name isEqualToString: [info name]] == YES)
|
||||
{
|
||||
[headers removeObjectAtIndex: count];
|
||||
}
|
||||
|
@ -2582,31 +2577,23 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
|
||||
/**
|
||||
* This method returns the info dictionary for the first header
|
||||
* whose name equals the supplied argument.
|
||||
* This method returns the first header whose name equals the supplied argument.
|
||||
*/
|
||||
- (NSDictionary*) headerNamed: (NSString*)name
|
||||
- (GSMimeHeader*) headerNamed: (NSString*)name
|
||||
{
|
||||
unsigned count = [headers count];
|
||||
unsigned index;
|
||||
NSArray *a = [self headersNamed: name];
|
||||
|
||||
name = [name lowercaseString];
|
||||
for (index = 0; index < count; index++)
|
||||
if ([a count] > 0)
|
||||
{
|
||||
NSDictionary *info = [headers objectAtIndex: index];
|
||||
NSString *other = [info objectForKey: @"Name"];
|
||||
|
||||
if ([name isEqualToString: other] == YES)
|
||||
{
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return [a objectAtIndex: 0];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns an array of info dictionaries for all headers
|
||||
* whose names equal the supplied argument.
|
||||
* This method returns an array of HSMimeHeader objects for all headers
|
||||
* whose names equal the supplied argument. For some special cases, the
|
||||
* method will try to generate headers if they are not present.
|
||||
*/
|
||||
- (NSArray*) headersNamed: (NSString*)name
|
||||
{
|
||||
|
@ -2614,18 +2601,37 @@ static NSCharacterSet *tokenSet = nil;
|
|||
unsigned index;
|
||||
NSMutableArray *array;
|
||||
|
||||
name = [name lowercaseString];
|
||||
name = [GSMimeHeader makeToken: name];
|
||||
array = [NSMutableArray array];
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
NSDictionary *info = [headers objectAtIndex: index];
|
||||
NSString *other = [info objectForKey: @"Name"];
|
||||
GSMimeHeader *info = [headers objectAtIndex: index];
|
||||
|
||||
if ([name isEqualToString: other] == YES)
|
||||
if ([name isEqualToString: [info name]] == YES)
|
||||
{
|
||||
[array addObject: info];
|
||||
}
|
||||
}
|
||||
if ([array count] == 0)
|
||||
{
|
||||
/*
|
||||
* If we have been asked for a Content-ID and there is none set,
|
||||
* we can generate one unique within this document.
|
||||
*/
|
||||
if ([name isEqualToString: @"content-id"] == YES)
|
||||
{
|
||||
NSString *val;
|
||||
GSMimeHeader *hdr;
|
||||
|
||||
val = [NSString stringWithFormat: @"GSMime%08x%08x", self, _count++];
|
||||
hdr = [[GSMimeHeader alloc] initWithName: name
|
||||
value: val
|
||||
parameters: nil];
|
||||
[self addHeader: hdr];
|
||||
[array addObject: hdr];
|
||||
RELEASE(hdr);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
|
@ -2643,8 +2649,27 @@ static NSCharacterSet *tokenSet = nil;
|
|||
*/
|
||||
- (BOOL) setContent: (id)newContent
|
||||
{
|
||||
ASSIGN(content, newContent);
|
||||
return YES;
|
||||
BOOL result = YES;
|
||||
|
||||
if ([newContent isKindOfClass: [NSString class]] == YES)
|
||||
{
|
||||
ASSIGNCOPY(content, newContent);
|
||||
}
|
||||
else if ([newContent isKindOfClass: [NSData class]] == YES)
|
||||
{
|
||||
ASSIGNCOPY(content, newContent);
|
||||
}
|
||||
else if ([newContent isKindOfClass: [NSArray class]] == YES)
|
||||
{
|
||||
newContent = [newContent mutableCopy];
|
||||
ASSIGN(content, newContent);
|
||||
RELEASE(newContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NO;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2652,30 +2677,27 @@ static NSCharacterSet *tokenSet = nil;
|
|||
* Any other headers with the same name will be removed from
|
||||
* the document.
|
||||
*/
|
||||
- (BOOL) setHeader: (NSDictionary*)info
|
||||
- (BOOL) setHeader: (GSMimeHeader*)info
|
||||
{
|
||||
NSString *name = [info objectForKey: @"Name"];
|
||||
unsigned count = [headers count];
|
||||
NSString *name = [info name];
|
||||
|
||||
if (name == nil)
|
||||
if (name != nil)
|
||||
{
|
||||
NSLog(@"setHeader: supplied with header info without 'Name' field");
|
||||
return NO;
|
||||
}
|
||||
unsigned count = [headers count];
|
||||
|
||||
/*
|
||||
* Remove any existing headers with this name.
|
||||
*/
|
||||
while (count-- > 0)
|
||||
{
|
||||
NSDictionary *tmp = [headers objectAtIndex: count];
|
||||
|
||||
if ([name isEqualToString: [tmp objectForKey: @"Name"]] == YES)
|
||||
/*
|
||||
* Remove any existing headers with this name.
|
||||
*/
|
||||
while (count-- > 0)
|
||||
{
|
||||
[headers removeObjectAtIndex: count];
|
||||
GSMimeHeader *tmp = [headers objectAtIndex: count];
|
||||
|
||||
if ([name isEqualToString: [tmp name]] == YES)
|
||||
{
|
||||
[headers removeObjectAtIndex: count];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [self addHeader: info];
|
||||
}
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ static void debugWrite(NSData *data)
|
|||
[parser parse: d];
|
||||
if ([parser isComplete] == YES)
|
||||
{
|
||||
NSDictionary *info;
|
||||
GSMimeHeader *info;
|
||||
NSString *val;
|
||||
|
||||
connectionState = idle;
|
||||
|
@ -273,7 +273,7 @@ static void debugWrite(NSData *data)
|
|||
[p parse: dat];
|
||||
if ([p isInBody] == YES || [d length] == 0)
|
||||
{
|
||||
NSDictionary *info;
|
||||
GSMimeHeader *info;
|
||||
NSString *val;
|
||||
|
||||
[p parse: nil];
|
||||
|
|
Loading…
Reference in a new issue