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/NSDictionary.h>
24 #import <NGExtensions/NGBase64Coding.h>
25 #import <NGExtensions/NSNull+misc.h>
26 #import <NGExtensions/NSObject+Logs.h>
27 #import <NGExtensions/NGQuotedPrintableCoding.h>
28 #import <NGExtensions/NSString+Encoding.h>
29 #import <NGExtensions/NSString+misc.h>
30 #import <SoObjects/SOGo/NSString+Utilities.h>
32 #import "UI/MailerUI/WOContext+UIxMailer.h"
33 #import "UIxMailRenderingContext.h"
34 #import "UIxMailSizeFormatter.h"
36 #import "UIxMailPartViewer.h"
38 @implementation UIxMailPartViewer
41 [flatContent release];
49 - (void)resetPathCaches {
50 /* this is called when -setPartPath: is called */
51 [flatContent release]; flatContent = nil;
53 - (void)resetBodyInfoCaches {
59 [self resetPathCaches];
60 [self resetBodyInfoCaches];
61 [partPath release]; partPath = nil;
62 [bodyInfo release]; bodyInfo = nil;
68 - (void)setPartPath:(NSArray *)_path {
69 if ([_path isEqual:partPath])
72 ASSIGN(partPath, _path);
73 [self resetPathCaches];
75 - (NSArray *)partPath {
79 - (void)setBodyInfo:(id)_info {
80 ASSIGN(bodyInfo, _info);
86 - (NSData *)flatContent {
87 if (flatContent != nil)
88 return [flatContent isNotNull] ? flatContent : nil;
91 [[[context mailRenderingContext] flatContentForPartPath:
92 [self partPath]] retain];
96 - (NSData *)decodedFlatContent {
99 enc = [[(NSDictionary *)[self bodyInfo]
100 objectForKey:@"encoding"] lowercaseString];
102 if ([enc isEqualToString:@"7bit"])
103 return [self flatContent];
105 if ([enc isEqualToString:@"8bit"]) // TODO: correct?
106 return [self flatContent];
108 if ([enc isEqualToString:@"base64"])
109 return [[self flatContent] dataByDecodingBase64];
111 if ([enc isEqualToString:@"quoted-printable"])
112 return [[self flatContent] dataByDecodingQuotedPrintable];
114 [self errorWithFormat:@"unsupported MIME encoding: %@", enc];
115 return [self flatContent];
118 - (NSStringEncoding)fallbackStringEncoding {
121 - (NSString *)flatContentAsString {
122 /* Note: we even have the line count in the body-info! */
127 if ((content = [self decodedFlatContent]) == nil) {
128 [self errorWithFormat:@"got no text content: %@",
129 [[self partPath] componentsJoinedByString:@"."]];
133 charset = [(NSDictionary *)
134 [(NSDictionary *)[self bodyInfo] objectForKey:@"parameterList"]
135 objectForKey:@"charset"];
136 charset = [charset lowercaseString];
138 // TODO: properly decode charset, might need to handle encoding?
140 if ([charset length] > 0) {
141 s = [NSString stringWithData: content usingEncodingNamed: charset];
144 s = [[NSString alloc] initWithData: content encoding: NSUTF8StringEncoding];
150 Note: this can happend with iCalendar invitations sent by Outlook 2002.
151 It will mark the content as UTF-8 but actually deliver it as
152 Latin-1 (or Windows encoding?).
154 [self errorWithFormat:@"could not convert content to text, charset: '%@'",
156 if ([self fallbackStringEncoding] > 0) {
157 s = [[NSString alloc] initWithData:content
158 encoding:[self fallbackStringEncoding]];
162 [self errorWithFormat:
163 @" an attempt to use fallback encoding failed to."];
172 - (NSString *)pathExtensionForType:(NSString *)_mt subtype:(NSString *)_st {
173 // TODO: support /etc/mime.types
175 if (![_mt isNotNull] || ![_st isNotNull])
177 if ([_mt length] == 0) return nil;
178 if ([_st length] == 0) return nil;
179 _mt = [_mt lowercaseString];
180 _st = [_st lowercaseString];
182 if ([_mt isEqualToString:@"image"]) {
183 if ([_st isEqualToString:@"gif"]) return @"gif";
184 if ([_st isEqualToString:@"jpeg"]) return @"jpg";
185 if ([_st isEqualToString:@"png"]) return @"png";
187 else if ([_mt isEqualToString:@"text"]) {
188 if ([_st isEqualToString:@"plain"]) return @"txt";
189 if ([_st isEqualToString:@"xml"]) return @"xml";
190 if ([_st isEqualToString:@"calendar"]) return @"ics";
191 if ([_st isEqualToString:@"x-vcard"]) return @"vcf";
193 else if ([_mt isEqualToString:@"message"]) {
194 if ([_st isEqualToString:@"rfc822"]) return @"mail";
196 else if ([_mt isEqualToString:@"application"]) {
197 if ([_st isEqualToString:@"pdf"]) return @"pdf";
202 - (NSString *)preferredPathExtension {
203 return [self pathExtensionForType:[[self bodyInfo] valueForKey:@"type"]
204 subtype:[[self bodyInfo] valueForKey:@"subtype"]];
207 - (NSString *)filename {
210 tmp = [[self bodyInfo] valueForKey:@"parameterList"];
211 if (![tmp isNotNull])
214 tmp = [tmp valueForKey:@"name"];
215 if (![tmp isNotNull])
217 if ([tmp length] == 0)
223 - (NSString *)filenameForDisplay {
226 if ((s = [self filename]) != nil)
229 s = [[self partPath] componentsJoinedByString:@"-"];
230 return ([s length] > 0)
231 ? [@"untitled-" stringByAppendingString:s]
235 - (NSFormatter *)sizeFormatter {
236 return [UIxMailSizeFormatter sharedMailSizeFormatter];
241 - (NSString *)pathToAttachmentObject {
242 /* this points to the SoObject representing the part, no modifications */
243 NSString *url, *n, *pext;
245 /* path to mail controller object */
247 url = [[self clientObject] baseURLInContext:context];
248 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
250 /* mail relative path to body-part */
252 if ([(n = [[self partPath] componentsJoinedByString:@"/"]) isNotNull]) {
253 /* eg this was nil for a draft containing an HTML message */
254 url = [url stringByAppendingString:n];
257 /* we currently NEED the extension for SoObject lookup (should be fixed) */
259 pext = [self preferredPathExtension];
260 if ([pext isNotNull] && [pext length] > 0) {
261 /* attach extension */
262 if ([url hasSuffix:@"/"]) {
263 /* this happens if the part is the root-content of the mail */
264 url = [url substringToIndex:([url length] - 1)];
266 url = [url stringByAppendingString:@"."];
267 url = [url stringByAppendingString:pext];
273 - (NSString *)pathToAttachment {
274 /* this generates a more beautiful 'download' URL for a part */
277 fn = [self filename];
279 if (![fn isNotNull] || ([fn length] == 0))
284 url = [self pathToAttachmentObject];
287 If we have an attachment name, we attach it, this is properly handled by
292 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
293 if (isdigit([fn characterAtIndex:0]))
294 url = [url stringByAppendingString:@"fn-"];
295 url = [url stringByAppendingString:[fn stringByEscapingURL]];
297 // TODO: should we check for a proper extension?
303 @end /* UIxMailPartViewer */