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 #include "UIxMailPartViewer.h"
23 #include "UIxMailRenderingContext.h"
24 #include "UIxMailSizeFormatter.h"
25 #include "../MailerUI/WOContext+UIxMailer.h"
26 #include <NGExtensions/NSString+Encoding.h>
29 @implementation UIxMailPartViewer
32 [self->flatContent release];
33 [self->bodyInfo release];
34 [self->partPath release];
40 - (void)resetPathCaches {
41 /* this is called when -setPartPath: is called */
42 [self->flatContent release]; self->flatContent = nil;
44 - (void)resetBodyInfoCaches {
50 [self resetPathCaches];
51 [self resetBodyInfoCaches];
52 [self->partPath release]; self->partPath = nil;
53 [self->bodyInfo release]; self->bodyInfo = nil;
59 - (void)setPartPath:(NSArray *)_path {
60 if ([_path isEqual:self->partPath])
63 ASSIGN(self->partPath, _path);
64 [self resetPathCaches];
66 - (NSArray *)partPath {
67 return self->partPath;
70 - (void)setBodyInfo:(id)_info {
71 ASSIGN(self->bodyInfo, _info);
74 return self->bodyInfo;
77 - (NSData *)flatContent {
78 if (self->flatContent != nil)
79 return [self->flatContent isNotNull] ? self->flatContent : nil;
82 [[[[self context] mailRenderingContext] flatContentForPartPath:
83 [self partPath]] retain];
84 return self->flatContent;
87 - (NSData *)decodedFlatContent {
90 enc = [[(NSDictionary *)[self bodyInfo]
91 objectForKey:@"encoding"] lowercaseString];
93 if ([enc isEqualToString:@"7bit"])
94 return [self flatContent];
96 if ([enc isEqualToString:@"8bit"]) // TODO: correct?
97 return [self flatContent];
99 if ([enc isEqualToString:@"base64"])
100 return [[self flatContent] dataByDecodingBase64];
102 if ([enc isEqualToString:@"quoted-printable"])
103 return [[self flatContent] dataByDecodingQuotedPrintable];
105 [self errorWithFormat:@"unsupported MIME encoding: %@", enc];
106 return [self flatContent];
109 - (NSStringEncoding)fallbackStringEncoding {
112 - (NSString *)flatContentAsString {
113 /* Note: we even have the line count in the body-info! */
118 if ((content = [self decodedFlatContent]) == nil) {
119 [self errorWithFormat:@"got no text content: %@",
120 [[self partPath] componentsJoinedByString:@"."]];
124 charset = [(NSDictionary *)
125 [(NSDictionary *)[self bodyInfo] objectForKey:@"parameterList"]
126 objectForKey:@"charset"];
127 charset = [charset lowercaseString];
129 // TODO: properly decode charset, might need to handle encoding?
131 if ([charset length] > 0) {
132 s = [NSString stringWithData: content usingEncodingNamed: charset];
135 s = [[NSString alloc] initWithData: content encoding: NSUTF8StringEncoding];
141 Note: this can happend with iCalendar invitations sent by Outlook 2002.
142 It will mark the content as UTF-8 but actually deliver it as
143 Latin-1 (or Windows encoding?).
145 [self errorWithFormat:@"could not convert content to text, charset: '%@'",
147 if ([self fallbackStringEncoding] > 0) {
148 s = [[NSString alloc] initWithData:content
149 encoding:[self fallbackStringEncoding]];
153 [self errorWithFormat:
154 @" an attempt to use fallback encoding failed to."];
163 - (NSString *)pathExtensionForType:(NSString *)_mt subtype:(NSString *)_st {
164 // TODO: support /etc/mime.types
166 if (![_mt isNotNull] || ![_st isNotNull])
168 if ([_mt length] == 0) return nil;
169 if ([_st length] == 0) return nil;
170 _mt = [_mt lowercaseString];
171 _st = [_st lowercaseString];
173 if ([_mt isEqualToString:@"image"]) {
174 if ([_st isEqualToString:@"gif"]) return @"gif";
175 if ([_st isEqualToString:@"jpeg"]) return @"jpg";
176 if ([_st isEqualToString:@"png"]) return @"png";
178 else if ([_mt isEqualToString:@"text"]) {
179 if ([_st isEqualToString:@"plain"]) return @"txt";
180 if ([_st isEqualToString:@"xml"]) return @"xml";
181 if ([_st isEqualToString:@"calendar"]) return @"ics";
182 if ([_st isEqualToString:@"x-vcard"]) return @"vcf";
184 else if ([_mt isEqualToString:@"message"]) {
185 if ([_st isEqualToString:@"rfc822"]) return @"mail";
187 else if ([_mt isEqualToString:@"application"]) {
188 if ([_st isEqualToString:@"pdf"]) return @"pdf";
193 - (NSString *)preferredPathExtension {
194 return [self pathExtensionForType:[[self bodyInfo] valueForKey:@"type"]
195 subtype:[[self bodyInfo] valueForKey:@"subtype"]];
198 - (NSString *)filename {
201 tmp = [[self bodyInfo] valueForKey:@"parameterList"];
202 if (![tmp isNotNull])
205 tmp = [tmp valueForKey:@"name"];
206 if (![tmp isNotNull])
208 if ([tmp length] == 0)
214 - (NSString *)filenameForDisplay {
217 if ((s = [self filename]) != nil)
220 s = [[self partPath] componentsJoinedByString:@"-"];
221 return ([s length] > 0)
222 ? [@"untitled-" stringByAppendingString:s]
226 - (NSFormatter *)sizeFormatter {
227 return [UIxMailSizeFormatter sharedMailSizeFormatter];
232 - (NSString *)pathToAttachmentObject {
233 /* this points to the SoObject representing the part, no modifications */
234 NSString *url, *n, *pext;
236 /* path to mail controller object */
238 url = [[self clientObject] baseURLInContext:[self context]];
239 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
241 /* mail relative path to body-part */
243 if ([(n = [[self partPath] componentsJoinedByString:@"/"]) isNotNull]) {
244 /* eg this was nil for a draft containing an HTML message */
245 url = [url stringByAppendingString:n];
248 /* we currently NEED the extension for SoObject lookup (should be fixed) */
250 pext = [self preferredPathExtension];
251 if ([pext isNotNull] && [pext length] > 0) {
252 /* attach extension */
253 if ([url hasSuffix:@"/"]) {
254 /* this happens if the part is the root-content of the mail */
255 url = [url substringToIndex:([url length] - 1)];
257 url = [url stringByAppendingString:@"."];
258 url = [url stringByAppendingString:pext];
264 - (NSString *)pathToAttachment {
265 /* this generates a more beautiful 'download' URL for a part */
268 fn = [self filename];
270 if (![fn isNotNull] || ([fn length] == 0))
275 url = [self pathToAttachmentObject];
278 If we have an attachment name, we attach it, this is properly handled by
283 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
284 if (isdigit([fn characterAtIndex:0]))
285 url = [url stringByAppendingString:@"fn-"];
286 url = [url stringByAppendingString:[fn stringByEscapingURL]];
288 // TODO: should we check for a proper extension?
294 @end /* UIxMailPartViewer */