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 "UIxMailPartViewer.h"
25 #import "UIxMailRenderingContext.h"
26 #import "UIxMailSizeFormatter.h"
27 #import "../MailerUI/WOContext+UIxMailer.h"
28 #import <NGExtensions/NSString+Encoding.h>
31 @implementation UIxMailPartViewer
34 [self->flatContent release];
35 [self->bodyInfo release];
36 [self->partPath release];
42 - (void)resetPathCaches {
43 /* this is called when -setPartPath: is called */
44 [self->flatContent release]; self->flatContent = nil;
46 - (void)resetBodyInfoCaches {
52 [self resetPathCaches];
53 [self resetBodyInfoCaches];
54 [self->partPath release]; self->partPath = nil;
55 [self->bodyInfo release]; self->bodyInfo = nil;
61 - (void)setPartPath:(NSArray *)_path {
62 if ([_path isEqual:self->partPath])
65 ASSIGN(self->partPath, _path);
66 [self resetPathCaches];
68 - (NSArray *)partPath {
69 return self->partPath;
72 - (void)setBodyInfo:(id)_info {
73 ASSIGN(self->bodyInfo, _info);
76 return self->bodyInfo;
79 - (NSData *)flatContent {
80 if (self->flatContent != nil)
81 return [self->flatContent isNotNull] ? self->flatContent : nil;
84 [[[[self context] mailRenderingContext] flatContentForPartPath:
85 [self partPath]] retain];
86 return self->flatContent;
89 - (NSData *)decodedFlatContent {
92 enc = [[(NSDictionary *)[self bodyInfo]
93 objectForKey:@"encoding"] lowercaseString];
95 if ([enc isEqualToString:@"7bit"])
96 return [self flatContent];
98 if ([enc isEqualToString:@"8bit"]) // TODO: correct?
99 return [self flatContent];
101 if ([enc isEqualToString:@"base64"])
102 return [[self flatContent] dataByDecodingBase64];
104 if ([enc isEqualToString:@"quoted-printable"])
105 return [[self flatContent] dataByDecodingQuotedPrintable];
107 [self errorWithFormat:@"unsupported MIME encoding: %@", enc];
108 return [self flatContent];
111 - (NSStringEncoding)fallbackStringEncoding {
114 - (NSString *)flatContentAsString {
115 /* Note: we even have the line count in the body-info! */
120 if ((content = [self decodedFlatContent]) == nil) {
121 [self errorWithFormat:@"got no text content: %@",
122 [[self partPath] componentsJoinedByString:@"."]];
126 charset = [(NSDictionary *)
127 [(NSDictionary *)[self bodyInfo] objectForKey:@"parameterList"]
128 objectForKey:@"charset"];
129 charset = [charset lowercaseString];
131 // TODO: properly decode charset, might need to handle encoding?
133 if ([charset length] > 0) {
134 s = [NSString stringWithData: content usingEncodingNamed: charset];
137 s = [[NSString alloc] initWithData: content encoding: NSUTF8StringEncoding];
143 Note: this can happend with iCalendar invitations sent by Outlook 2002.
144 It will mark the content as UTF-8 but actually deliver it as
145 Latin-1 (or Windows encoding?).
147 [self errorWithFormat:@"could not convert content to text, charset: '%@'",
149 if ([self fallbackStringEncoding] > 0) {
150 s = [[NSString alloc] initWithData:content
151 encoding:[self fallbackStringEncoding]];
155 [self errorWithFormat:
156 @" an attempt to use fallback encoding failed to."];
165 - (NSString *)pathExtensionForType:(NSString *)_mt subtype:(NSString *)_st {
166 // TODO: support /etc/mime.types
168 if (![_mt isNotNull] || ![_st isNotNull])
170 if ([_mt length] == 0) return nil;
171 if ([_st length] == 0) return nil;
172 _mt = [_mt lowercaseString];
173 _st = [_st lowercaseString];
175 if ([_mt isEqualToString:@"image"]) {
176 if ([_st isEqualToString:@"gif"]) return @"gif";
177 if ([_st isEqualToString:@"jpeg"]) return @"jpg";
178 if ([_st isEqualToString:@"png"]) return @"png";
180 else if ([_mt isEqualToString:@"text"]) {
181 if ([_st isEqualToString:@"plain"]) return @"txt";
182 if ([_st isEqualToString:@"xml"]) return @"xml";
183 if ([_st isEqualToString:@"calendar"]) return @"ics";
184 if ([_st isEqualToString:@"x-vcard"]) return @"vcf";
186 else if ([_mt isEqualToString:@"message"]) {
187 if ([_st isEqualToString:@"rfc822"]) return @"mail";
189 else if ([_mt isEqualToString:@"application"]) {
190 if ([_st isEqualToString:@"pdf"]) return @"pdf";
195 - (NSString *)preferredPathExtension {
196 return [self pathExtensionForType:[[self bodyInfo] valueForKey:@"type"]
197 subtype:[[self bodyInfo] valueForKey:@"subtype"]];
200 - (NSString *)filename {
203 tmp = [[self bodyInfo] valueForKey:@"parameterList"];
204 if (![tmp isNotNull])
207 tmp = [tmp valueForKey:@"name"];
208 if (![tmp isNotNull])
210 if ([tmp length] == 0)
216 - (NSString *)filenameForDisplay {
219 if ((s = [self filename]) != nil)
222 s = [[self partPath] componentsJoinedByString:@"-"];
223 return ([s length] > 0)
224 ? [@"untitled-" stringByAppendingString:s]
228 - (NSFormatter *)sizeFormatter {
229 return [UIxMailSizeFormatter sharedMailSizeFormatter];
234 - (NSString *)pathToAttachmentObject {
235 /* this points to the SoObject representing the part, no modifications */
236 NSString *url, *n, *pext;
238 /* path to mail controller object */
240 url = [[self clientObject] baseURLInContext:[self context]];
241 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
243 /* mail relative path to body-part */
245 if ([(n = [[self partPath] componentsJoinedByString:@"/"]) isNotNull]) {
246 /* eg this was nil for a draft containing an HTML message */
247 url = [url stringByAppendingString:n];
250 /* we currently NEED the extension for SoObject lookup (should be fixed) */
252 pext = [self preferredPathExtension];
253 if ([pext isNotNull] && [pext length] > 0) {
254 /* attach extension */
255 if ([url hasSuffix:@"/"]) {
256 /* this happens if the part is the root-content of the mail */
257 url = [url substringToIndex:([url length] - 1)];
259 url = [url stringByAppendingString:@"."];
260 url = [url stringByAppendingString:pext];
266 - (NSString *)pathToAttachment {
267 /* this generates a more beautiful 'download' URL for a part */
270 fn = [self filename];
272 if (![fn isNotNull] || ([fn length] == 0))
277 url = [self pathToAttachmentObject];
280 If we have an attachment name, we attach it, this is properly handled by
285 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
286 if (isdigit([fn characterAtIndex:0]))
287 url = [url stringByAppendingString:@"fn-"];
288 url = [url stringByAppendingString:[fn stringByEscapingURL]];
290 // TODO: should we check for a proper extension?
296 @end /* UIxMailPartViewer */