2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #import <Foundation/NSArray.h>
23 #import <Foundation/NSDictionary.h>
25 #import <NGExtensions/NGBase64Coding.h>
26 #import <NGExtensions/NSNull+misc.h>
27 #import <NGExtensions/NSObject+Logs.h>
28 #import <NGExtensions/NGQuotedPrintableCoding.h>
29 #import <NGExtensions/NSString+Encoding.h>
30 #import <NGExtensions/NSString+misc.h>
32 #import <SoObjects/SOGo/NSString+Utilities.h>
33 #import <SoObjects/Mailer/SOGoMailBodyPart.h>
35 #import "UI/MailerUI/WOContext+UIxMailer.h"
36 #import "UIxMailRenderingContext.h"
37 #import "UIxMailSizeFormatter.h"
39 #import "UIxMailPartViewer.h"
41 @implementation UIxMailPartViewer
45 [flatContent release];
53 - (void) resetPathCaches
55 /* this is called when -setPartPath: is called */
56 [flatContent release]; flatContent = nil;
59 - (void) resetBodyInfoCaches
67 [self resetPathCaches];
68 [self resetBodyInfoCaches];
78 - (void) setPartPath: (NSArray *) _path
80 if ([_path isEqual: partPath])
83 ASSIGN(partPath, _path);
85 [self resetPathCaches];
88 - (NSArray *) partPath
93 - (void) setBodyInfo: (id) _info
95 ASSIGN(bodyInfo, _info);
103 - (NSData *) flatContent
105 if (flatContent != nil)
106 return [flatContent isNotNull] ? flatContent : nil;
109 [[[context mailRenderingContext] flatContentForPartPath:
114 - (NSData *) decodedFlatContent
118 enc = [[bodyInfo objectForKey:@"encoding"] lowercaseString];
120 if ([enc isEqualToString:@"7bit"])
121 return [self flatContent];
123 if ([enc isEqualToString:@"8bit"]) // TODO: correct?
124 return [self flatContent];
126 if ([enc isEqualToString:@"base64"])
127 return [[self flatContent] dataByDecodingBase64];
129 if ([enc isEqualToString:@"quoted-printable"])
130 return [[self flatContent] dataByDecodingQuotedPrintable];
132 [self errorWithFormat:@"unsupported MIME encoding: %@", enc];
134 return [self flatContent];
142 NSString *currentPart;
146 currentObject = [self clientObject];
147 parts = [partPath objectEnumerator];
148 currentPart = [parts nextObject];
151 currentObject = [currentObject lookupName: currentPart
154 currentPart = [parts nextObject];
157 content = [currentObject fetchBLOB];
162 - (NSStringEncoding) fallbackStringEncoding
167 - (NSString *) flatContentAsString
169 /* Note: we even have the line count in the body-info! */
174 content = [self decodedFlatContent];
177 charset = [[bodyInfo objectForKey:@"parameterList"]
178 objectForKey: @"charset"];
179 charset = [charset lowercaseString];
180 if (![charset length]
181 || [charset isEqualToString: @"us-ascii"])
183 s = [[NSString alloc] initWithData: content
184 encoding: NSISOLatin1StringEncoding];
189 s = [NSString stringWithData: content
190 usingEncodingNamed: charset];
193 /* latin 1 is used as a 8bit fallback charset... but does this
194 encoding accept any byte from 0 to 255? */
195 s = [[NSString alloc] initWithData: content
196 encoding: NSISOLatin1StringEncoding];
204 Note: this can happend with iCalendar invitations sent by Outlook 2002.
205 It will mark the content as UTF-8 but actually deliver it as
206 Latin-1 (or Windows encoding?).
208 [self errorWithFormat:@"could not convert content to text, charset: '%@'",
210 if ([self fallbackStringEncoding] > 0)
212 s = [[NSString alloc] initWithData:content
213 encoding: [self fallbackStringEncoding]];
217 [self errorWithFormat:
218 @"an attempt to use fallback encoding failed to."];
224 [self errorWithFormat:@"got no text content: %@",
225 [partPath componentsJoinedByString:@"."]];
234 - (NSString *) pathExtensionForType: (NSString *) _mt
235 subtype: (NSString *) _st
237 // TODO: support /etc/mime.types
239 if (![_mt isNotNull] || ![_st isNotNull])
241 if ([_mt length] == 0) return nil;
242 if ([_st length] == 0) return nil;
243 _mt = [_mt lowercaseString];
244 _st = [_st lowercaseString];
246 if ([_mt isEqualToString:@"image"]) {
247 if ([_st isEqualToString:@"gif"]) return @"gif";
248 if ([_st isEqualToString:@"jpeg"]) return @"jpg";
249 if ([_st isEqualToString:@"png"]) return @"png";
251 else if ([_mt isEqualToString:@"text"]) {
252 if ([_st isEqualToString:@"plain"]) return @"txt";
253 if ([_st isEqualToString:@"xml"]) return @"xml";
254 if ([_st isEqualToString:@"calendar"]) return @"ics";
255 if ([_st isEqualToString:@"x-vcard"]) return @"vcf";
257 else if ([_mt isEqualToString:@"message"]) {
258 if ([_st isEqualToString:@"rfc822"]) return @"mail";
260 else if ([_mt isEqualToString:@"application"]) {
261 if ([_st isEqualToString:@"pdf"]) return @"pdf";
266 - (NSString *) preferredPathExtension
268 return [self pathExtensionForType: [bodyInfo valueForKey:@"type"]
269 subtype: [bodyInfo valueForKey:@"subtype"]];
272 - (NSString *) filename
274 NSDictionary *parameters;
278 parameters = [bodyInfo valueForKey: @"parameterList"];
280 filename = [parameters valueForKey: @"name"];
284 parameters = [[bodyInfo valueForKey: @"disposition"]
285 valueForKey: @"parameterList"];
286 filename = [parameters valueForKey: @"filename"];
292 - (NSString *) filenameForDisplay
296 if ((s = [self filename]) != nil)
299 s = [partPath componentsJoinedByString:@"-"];
300 return ([s length] > 0)
301 ? [@"untitled-" stringByAppendingString:s]
305 - (NSFormatter *) sizeFormatter
307 return [UIxMailSizeFormatter sharedMailSizeFormatter];
312 - (NSString *) pathToAttachmentObject
314 /* this points to the SoObject representing the part, no modifications */
317 /* path to mail controller object */
319 url = [[self clientObject] baseURLInContext:context];
320 if (![url hasSuffix: @"/"])
321 url = [url stringByAppendingString: @"/"];
323 /* mail relative path to body-part */
325 /* eg this was nil for a draft containing an HTML message */
326 if ([(n = [partPath componentsJoinedByString:@"/"]) isNotNull])
327 url = [url stringByAppendingString:n];
332 - (NSString *) pathToAttachment
334 /* this generates a more beautiful 'download' URL for a part */
336 NSMutableString *url;
338 fn = [self filename];
342 url = [NSMutableString stringWithString: [self pathToAttachmentObject]];
345 If we have an attachment name, we attach it, this is properly handled by
349 if (![url hasSuffix: @"/"])
350 [url appendString: @"/"];
351 if (isdigit([url characterAtIndex: 0]))
352 [url appendString: @"fn-"];
353 [url appendString: [fn stringByEscapingURL]];
354 // TODO: should we check for a proper extension?
362 @end /* UIxMailPartViewer */