2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #import "Mime2XmlTool.h"
24 #import <NGStreams/NGStreams.h>
25 #import <NGMime/NGMime.h>
26 #import <NGMail/NGMail.h>
28 @interface Mime2XmlTool(Privates)
29 - (BOOL)_outputPartAsXML:(id<NGMimePart>)_part;
32 @implementation Mime2XmlTool
34 - (NSUserDefaults *)userDefaults {
35 return [NSUserDefaults standardUserDefaults];
42 for (i = 0; i < self->outIndent; i++)
46 - (BOOL)_outputMultipartBody:(NGMimeMultipartBody *)_body {
52 e = [[_body parts] objectEnumerator];
53 while ((part = [e nextObject]))
54 [self _outputPartAsXML:part];
60 - (BOOL)_outputStringBody:(NSString *)body {
62 printf("<body charlen='%i'>", [body length]);
63 if ([body length] > 256) {
64 body = [body substringToIndex:255];
65 printf("%s", [body cString]);
70 - (BOOL)_outputDataBody:(NSData *)body {
72 printf("<body><data size='%i'>...</data></body>\n",
76 - (BOOL)_outputPartBody:(id<NGMimePart>)body {
79 [self _outputPartAsXML:(id<NGMimePart>)body];
84 - (BOOL)_outputMultiPartBody:(id<NGMimePart>)body {
86 printf("<body multipart='true'>\n");
88 [self _outputMultipartBody:(id)body];
95 - (BOOL)_outputHeaderField:(NSString *)_field value:(id)_value {
100 clazz = [_value class];
101 printf("<h name=\"%s\"", [_field cString]);
104 s = [_value stringValue];
105 s = [s stringByEscapingXMLString];
106 printf("%s", [s cString]);
111 - (BOOL)_outputPartHeaders:(id<NGMimePart>)_part {
112 NSEnumerator *headerFields;
113 NSString *headerField;
115 headerFields = [_part headerFieldNames];
116 while ((headerField = [headerFields nextObject])) {
120 vals = [_part valuesOfHeaderFieldWithName:headerField];
121 while ((value = [vals nextObject])) {
122 [self _outputHeaderField:headerField value:value];
128 - (BOOL)_outputPartAsXML:(id<NGMimePart>)_part {
133 NSLog(@"got no part ...");
138 printf("<part ptr='0x%p'", (unsigned int)_part);
140 if ([_part conformsToProtocol:@protocol(NGMimePart)]) {
141 if ((tmp = [_part contentType]))
142 printf(" content-type='%s'", [[tmp stringValue] cString]);
143 if ((tmp = [_part encoding]))
144 printf(" encoding='%s'", [[tmp stringValue] cString]);
145 if ((tmp = [_part contentId]))
146 printf(" content-id='%s'", [[tmp stringValue] cString]);
147 if ((tmp = [_part contentLanguage]))
148 printf(" content-language='%s'", [[tmp stringValue] cString]);
149 if ((tmp = [_part contentMd5]))
150 printf(" content-md5='%s'", [[tmp stringValue] cString]);
156 [self _outputPartHeaders:_part];
160 if ((body = [_part body])) {
161 if ([body isKindOfClass:[NSString class]])
162 [self _outputStringBody:body];
163 else if ([body isKindOfClass:[NSData class]])
164 [self _outputDataBody:body];
165 else if ([body conformsToProtocol:@protocol(NGMimePart)]) {
167 Note: an NSData is also a MIME part, because of this
168 a check for NSData needs to be done first !
170 [self _outputPartBody:body];
172 else if ([body isKindOfClass:[NGMimeMultipartBody class]]) {
173 [self _outputMultiPartBody:body];
176 NSLog(@"unknown body class: %@", NSStringFromClass(body));
185 - (BOOL)outputPartAsXML:(id<NGMimePart>)_part {
187 printf("<?xml version='1.0' encoding='ISO-8859-1'?>\n");
188 return [self _outputPartAsXML:_part];
191 - (BOOL)outputPartAsMime:(id<NGMimePart>)_part {
195 - (BOOL)outputPart:(id<NGMimePart>)_part {
196 NSUserDefaults *ud = [self userDefaults];
197 NSAutoreleasePool *pool;
201 pool = [[NSAutoreleasePool alloc] init];
203 out = [ud stringForKey:@"out"];
204 if ([out length] == 0)
206 else if ([out isEqualToString:@"xml"])
207 result = [self outputPartAsXML:_part];
208 else if ([out isEqualToString:@"mime"])
209 result = [self outputPartAsMime:_part];
211 NSLog(@"unknown output module: %@", out);
221 - (id)parser:(NGMimePartParser *)_parser
222 parseHeaderField:(NSString *)_name
225 if (self->rejectAllFields) {
226 if ([_name hasPrefix:@"content-"]) {
229 s = [[NSString alloc] initWithData:_data
230 encoding:NSISOLatin1StringEncoding];
231 return [s autorelease];
240 - (void)parser:(NGMimePartParser *)_parser
241 didParseHeader:(NGHashMap *)_header
243 //NSLog(@"got header: %@", _header);
245 - (BOOL)parser:(NGMimePartParser *)_parser
246 keepHeaderField:(NSString *)_name
249 if ([_name hasPrefix:@"content-"])
252 return self->rejectAllFields ? NO : YES;
257 - (id<NGMimePart>)parseFile:(NSString *)_path useStreams:(BOOL)_streams {
258 NSAutoreleasePool *pool;
259 NGMimePartParser *parser;
262 pool = [[NSAutoreleasePool alloc] init];
267 parser = [[[NGMimeMessageParser alloc] init] autorelease];
269 if (self->useDelegate)
270 [parser setDelegate:self];
272 /* create input object */
275 NGFileStream *stream;
277 stream = [[[NGFileStream alloc] initWithPath:_path] autorelease];
278 if (![stream openInMode:@"r"]) {
279 NSLog(@"could not open stream for reading: '%@'\n exception: %@",
280 _path, [stream lastException]);
284 sel = @selector(parsePartFromStream:);
290 if ((data = [NSData dataWithContentsOfMappedFile:_path]) == nil) {
291 NSLog(@"could not get data for path: '%@'", _path);
295 sel = @selector(parsePartFromData:);
301 if ([[self userDefaults] boolForKey:@"noparse"])
304 part = [parser performSelector:sel withObject:input];
306 part = [part retain];
309 return [part autorelease];
312 - (BOOL)processFile:(NSString *)_path {
313 NSProcessInfo *pi = [NSProcessInfo processInfo];
314 NSUserDefaults *ud = [self userDefaults];
316 NSAutoreleasePool *pool;
318 NSLog(@"process: %@", _path);
322 pool = [[NSAutoreleasePool alloc] init];
324 NSTimeInterval startTime, endTime;
325 unsigned int startSize, endSize;
326 int i, preRepeatCount;
328 /* first some useless parsing for profiling */
330 preRepeatCount = self->preloops;
331 for (i = 0; i < preRepeatCount; i++) {
332 NSAutoreleasePool *pool;
334 startTime = [[NSDate date] timeIntervalSince1970];
335 startSize = [pi virtualMemorySize];
337 pool = [[NSAutoreleasePool alloc] init];
338 part = [self parseFile:_path useStreams:[ud boolForKey:@"streams"]];
341 endSize = [pi virtualMemorySize];
342 endTime = [[NSDate date] timeIntervalSince1970];
346 if ([ud boolForKey:@"statistics"]) {
348 "parsing time [%2i]: %.3fs, "
349 "vmem-diff: %8i (%4iK,%4iM), vmem: %8i (%4iK,%4iM))\n",
350 i, (endTime-startTime),
351 (endSize - startSize),
352 (endSize - startSize) / 1024,
353 (endSize - startSize) / 1024 / 1024,
354 endSize, endSize/1024, endSize/1024/1024);
358 /* the "real" parser (remembers the part ...) */
360 startTime = [[NSDate date] timeIntervalSince1970];
361 startSize = [pi virtualMemorySize];
362 part = [self parseFile:_path useStreams:[ud boolForKey:@"streams"]];
363 endSize = [pi virtualMemorySize];
364 endTime = [[NSDate date] timeIntervalSince1970];
368 if ([ud boolForKey:@"statistics"]) {
370 "parsing time: %.3fs, vmem-diff: %8i, vmem: %8i\n",
371 (endTime-startTime), (endSize - startSize), endSize);
374 part = [part retain];
376 part = [part autorelease];
379 NSLog(@"could not parse a part from path: '%@'", _path);
384 [self outputPart:part];
391 fprintf(stderr, "usage: mime2xml <file>*\n");
392 fprintf(stderr, " -preloops <n>\n");
393 fprintf(stderr, " -statistics YES|NO\n");
394 fprintf(stderr, " -streams YES|NO\n");
395 fprintf(stderr, " -noparse YES|NO\n");
396 fprintf(stderr, " -delegate YES|NO\n");
397 fprintf(stderr, " -parsefields YES|NO\n");
401 - (int)runWithArguments:(NSArray *)_args {
402 NSUserDefaults *ud = [self userDefaults];
406 self->parseFields = [ud boolForKey:@"parsefields"];
407 self->useDelegate = [ud boolForKey:@"delegate"];
408 self->preloops = [ud integerForKey:@"preloops"];
409 self->rejectAllFields = [ud boolForKey:@"rejectAllFields"];
411 _args = [_args subarrayWithRange:NSMakeRange(1, [_args count] - 1)];
412 if ([_args count] == 0)
415 e = [_args objectEnumerator];
416 while ((f = [e nextObject])) {
417 NSAutoreleasePool *pool;
419 pool = [[NSAutoreleasePool alloc] init];
420 [self processFile:f];
427 @end /* Mime2XmlTool */