1/* 2 Copyright (C) 2007-2009 Inverse inc. 3 Copyright (C) 2004 SKYRIX Software AG 4 5 This file is part of SOGo. 6 7 SOGo is free software; you can redistribute it and/or modify it under 8 the terms of the GNU Lesser General Public License as published by the 9 Free Software Foundation; either version 2, or (at your option) any 10 later version. 11 12 SOGo is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with OGo; see the file COPYING. If not, write to the 19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 20 02111-1307, USA. 21*/ 22 23#import <Foundation/NSNull.h> 24 25#import <NGExtensions/NSObject+Logs.h> 26 27#import <UI/MailerUI/WOContext+UIxMailer.h> 28 29#import "UIxMailPartViewer.h" 30#import "UIxMailRenderingContext.h" 31 32/* 33 UIxMailPartAlternativeViewer 34 35 Display multipart/alternative parts. Most common application is for messages 36 which contain text/html and text/plain, but it is also used in other 37 contexts, eg in OGo appointment mails. 38 39 TODO: We might want to give the user the possibility to access all parts 40 of the alternative set. 41*/ 42 43@interface UIxMailPartAlternativeViewer : UIxMailPartViewer 44{ 45 id childInfo; 46 NSUInteger childIndex; 47} 48 49@end 50 51@implementation UIxMailPartAlternativeViewer 52 53- (void) dealloc 54{ 55 [childInfo release]; 56 [super dealloc]; 57} 58 59/* caches */ 60 61- (void) resetBodyInfoCaches 62{ 63 [childInfo release]; childInfo = nil; 64 childIndex = 0; 65 [super resetBodyInfoCaches]; 66} 67 68/* part selection */ 69 70- (NSArray *) childPartTypes 71{ 72 NSMutableArray *types; 73 NSUInteger i, count; 74 NSArray *childParts; 75 76 childParts = [[self bodyInfo] valueForKey:@"parts"]; 77 count = [childParts count]; 78 types = [NSMutableArray arrayWithCapacity:count]; 79 80 for (i = 0; i < count; i++) { 81 NSString *mt, *st; 82 83 mt = [[[childParts objectAtIndex:i] valueForKey:@"type"] lowercaseString]; 84 st = [[[childParts objectAtIndex:i] valueForKey:@"subtype"] 85 lowercaseString]; 86 mt = [[mt stringByAppendingString:@"/"] stringByAppendingString:st]; 87 [types addObject:mt ? (id)mt : (id)[NSNull null]]; 88 } 89 return types; 90} 91 92- (NSUInteger) _preferredTypesPart: (NSArray *) types 93{ 94 NSUInteger count, max; 95 NSUInteger part; 96 const NSString *priorities[] = { @"multipart/related", @"multipart/mixed", 97 @"text/calendar", @"text/html", 98 @"text/plain" }; 99 100 part = NSNotFound; 101 102 max = sizeof (priorities) / sizeof (NSString *); 103 for (count = 0; count < max; count++) 104 { 105 part = [types indexOfObject: priorities[count]]; 106 if (part != NSNotFound) 107 break; 108 } 109 110 return part; 111} 112 113- (int) _selectPartIndexFromTypes: (NSArray *) _types 114{ 115 /* returns the index of the selected part or NSNotFound */ 116 NSUInteger count, max, part; 117 118 part = [self _preferredTypesPart: _types]; 119 if (part == NSNotFound) 120 { 121 max = [_types count]; 122 /* then we scan for other text types and choose the first one found */ 123 for (count = 0; count < max; count++) 124 if ([[_types objectAtIndex: count] hasPrefix:@"text/"]) 125 { 126 part = count; 127 break; 128 } 129 } 130 131 if (part == NSNotFound) 132 part = 0; /* as a fallback, we select the first available part */ 133 134 return part; 135} 136 137- (void) selectChildInfo 138{ 139 NSUInteger idx; 140 141 [childInfo release]; childInfo = nil; 142 childIndex = 0; 143 144 idx = [self _selectPartIndexFromTypes: [self childPartTypes]]; 145 if (idx == NSNotFound) 146 { 147 [self errorWithFormat:@"could not select a part of types: %@", 148 [self childPartTypes]]; 149 return; 150 } 151 152 childIndex = idx + 1; 153 childInfo = 154 [[[[self bodyInfo] valueForKey:@"parts"] objectAtIndex:idx] retain]; 155} 156 157/* accessors */ 158 159- (id) childInfo 160{ 161 if (!childInfo) 162 [self selectChildInfo]; 163 164 return childInfo; 165} 166 167- (NSUInteger) childIndex 168{ 169 if (!childIndex) 170 [self selectChildInfo]; 171 172 return childIndex - 1; 173} 174 175- (NSString *) childPartName 176{ 177 return [NSString stringWithFormat: @"%u", 178 (unsigned int) ([self childIndex] + 1)]; 179} 180 181- (id) childPartPath 182{ 183 NSArray *pp; 184 185 pp = [self partPath]; 186 return [pp count] > 0 187 ? (id)[pp arrayByAddingObject:[self childPartName]] 188 : (id)[NSArray arrayWithObject:[self childPartName]]; 189} 190 191/* nested viewers */ 192 193- (id) contentViewerComponent 194{ 195 id info; 196 197 info = [self childInfo]; 198 return [[[self context] mailRenderingContext] viewerForBodyInfo:info]; 199} 200 201@end /* UIxMailPartAlternativeViewer */ 202