From 6a3e04d97b815fb60e88a4f6ba952e85ea06828b Mon Sep 17 00:00:00 2001 From: wolfgang Date: Thu, 15 Feb 2007 21:16:35 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1025 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 25 + SOPE/NGCards/CardGroup.h | 2 +- SOPE/NGCards/CardGroup.m | 27 + SOPE/NGCards/ChangeLog | 4 + .../Appointments/SOGoAppointmentObject.h | 5 - .../Appointments/SOGoAppointmentObject.m | 82 +-- .../Appointments/SOGoCalendarComponent.h | 4 +- .../Appointments/SOGoCalendarComponent.m | 40 +- SoObjects/Appointments/SOGoTaskObject.h | 5 - SoObjects/Appointments/SOGoTaskObject.m | 25 +- SoObjects/Appointments/product.plist | 3 +- SoObjects/Mailer/SOGoMailObject.m | 3 +- SoObjects/SOGo/SOGoPermissions.h | 3 + SoObjects/SOGo/SOGoPermissions.m | 4 + .../French.lproj/Localizable.strings | 2 + UI/MailPartViewers/GNUmakefile | 2 +- .../UIxMailPartAlternativeViewer.m | 5 +- UI/MailPartViewers/UIxMailPartHTMLViewer.m | 473 +++++++++++++++++- UI/MailPartViewers/UIxMailPartICalViewer.m | 2 +- UI/MailPartViewers/UIxMailPartViewer.m | 10 +- UI/MailPartViewers/UIxMailRenderingContext.m | 5 +- UI/Scheduler/UIxAppointmentEditor.m | 4 +- UI/Scheduler/UIxAppointmentView.m | 23 +- UI/Scheduler/UIxComponentEditor.m | 16 +- UI/Scheduler/UIxTaskEditor.m | 6 +- UI/Scheduler/UIxTaskView.m | 23 +- UI/Scheduler/product.plist | 4 +- .../MailPartViewers/UIxMailPartHTMLViewer.wox | 30 +- UI/WebServerResources/MailerUI.css | 36 +- 29 files changed, 655 insertions(+), 218 deletions(-) diff --git a/ChangeLog b/ChangeLog index 90bbbff2..832b7b06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2007-02-15 Wolfgang Sourdeau + + * UI/MailPartViewers/UIxMailRenderingContext.m: returns the + alternativeViewer a multipart/related message is being handled. + + * UI/MailPartViewers/UIxMailPartHTMLViewer.m: reimplemented module + from scratch. + + * UI/MailPartViewers/UIxMailPartAlternativeViewer.m: select the + text/html component before text/plain. + + * SoObjects/Mailer/SOGoMailObject.m ([SOGoMailObject + -addRequiredKeysOfStructure:path:toArray:recurse:]): accepts the + fetching of HTML parts. + + * SoObjects/Appointments/SOGoCalendarComponent.m + ([SOGoCalendarComponent -componentTag]): new template method that + returns the vcalendar tag of the current object. + ([SOGoCalendarComponent -component]): new method that returns the + first object matching [self componentTag] within the current + calendar object. This method replaces 'firstEventInCalendar:' as + well as "firstTaskInCalendar:". + ([SOGoCalendarComponent -roleOfUser:logininContext:context]): + moved method from SOGoAppointmentObject.m. + 2007-02-13 Wolfgang Sourdeau * UI/Scheduler/UIxCalMulticolumnDayView.[hm]: new daily view diff --git a/SOPE/NGCards/CardGroup.h b/SOPE/NGCards/CardGroup.h index 3108f8b9..6800f076 100644 --- a/SOPE/NGCards/CardGroup.h +++ b/SOPE/NGCards/CardGroup.h @@ -50,6 +50,7 @@ - (void) addChildren: (NSArray *) someChildren; - (NSArray *) children; +- (CardElement *) firstChildWithTag: (NSString *) aTag; - (NSArray *) childrenWithTag: (NSString *) aTag; - (NSArray *) childrenWithAttribute: (NSString *) anAttribute havingValue: (NSString *) aValue; @@ -64,7 +65,6 @@ types: (NSArray *) someTypes singleValue: (NSString *) aValue; - - (CardGroup *) groupWithClass: (Class) groupClass; - (void) setChildrenAsCopy: (NSMutableArray *) someChildren; diff --git a/SOPE/NGCards/CardGroup.m b/SOPE/NGCards/CardGroup.m index b7b60ca7..ae375d46 100644 --- a/SOPE/NGCards/CardGroup.m +++ b/SOPE/NGCards/CardGroup.m @@ -232,6 +232,33 @@ static NGCardsSaxHandler *sax = nil; [self addChild: aChild]; } +- (CardElement *) firstChildWithTag: (NSString *) aTag; +{ + Class mappedClass; + CardElement *child, *mappedChild; + NSArray *existing; + + existing = [self childrenWithTag: aTag]; + if ([existing count]) + { + child = [existing objectAtIndex: 0]; + mappedClass = [self classForTag: [aTag uppercaseString]]; + if (mappedClass) + { + if ([child isKindOfClass: [CardGroup class]]) + mappedChild = [(CardGroup *) child groupWithClass: mappedClass]; + else + mappedChild = [child elementWithClass: mappedClass]; + } + else + mappedChild = child; + } + else + mappedChild = nil; + + return mappedChild; +} + - (void) addChildren: (NSArray *) someChildren { CardElement *currentChild; diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index e5dea661..6b01b649 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,7 @@ +2007-02-15 Wolfgang Sourdeau + + * CardGroup.m ([CardGroup -firstChildWithTag:aTag]): new method. + 2007-02-09 Wolfgang Sourdeau * CardGroup.m ([CardGroup +cardParser]): find the correct parser diff --git a/SoObjects/Appointments/SOGoAppointmentObject.h b/SoObjects/Appointments/SOGoAppointmentObject.h index ab41219b..17e9b24b 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.h +++ b/SoObjects/Appointments/SOGoAppointmentObject.h @@ -46,11 +46,6 @@ @interface SOGoAppointmentObject : SOGoCalendarComponent -/* accessors */ - -- (iCalEvent *) event; -- (iCalEvent *) firstEventFromCalendar: (iCalCalendar *) calendar; - /* folder management */ - (id) lookupHomeFolderForUID: (NSString *) _uid inContext: (id)_ctx; diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index e9c9b73f..b2b8e1f9 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -28,6 +28,7 @@ #import #import +#import #import "iCalEntityObject+Agenor.h" @@ -37,11 +38,9 @@ @implementation SOGoAppointmentObject -/* accessors */ - -- (iCalEvent *) event +- (NSString *) componentTag { - return [self firstEventFromCalendar: [self calendar]]; + return @"vevent"; } /* iCal handling */ @@ -77,22 +76,23 @@ /* add attendees */ - for (i = 0; i < count; i++) { - iCalPerson *person; + for (i = 0; i < count; i++) + { + iCalPerson *person; - person = [attendees objectAtIndex:i]; - email = [person rfc822Email]; - if (![email isNotNull]) continue; + person = [attendees objectAtIndex:i]; + email = [person rfc822Email]; + if (![email isNotNull]) continue; - uid = [um getUIDForEmail:email]; - if (![uid isNotNull]) { - [self logWithFormat:@"Note: got no uid for email: '%@'", email]; - continue; + uid = [um getUIDForEmail:email]; + if (![uid isNotNull]) { + [self logWithFormat:@"Note: got no uid for email: '%@'", email]; + continue; + } + if (![uids containsObject:uid]) + [uids addObject:uid]; } - if (![uids containsObject:uid]) - [uids addObject:uid]; - } - + return uids; } @@ -186,21 +186,6 @@ return allErrors; } -- (iCalEvent *) firstEventFromCalendar: (iCalCalendar *) aCalendar -{ - iCalEvent *event; - NSArray *events; - - events = [aCalendar childrenWithTag: @"vevent"]; - if ([events count]) - event = (iCalEvent *) [[events objectAtIndex: 0] - groupWithClass: [iCalEvent class]]; - else - event = nil; - - return event; -} - /* "iCal multifolder saves" */ - (NSException *) saveContentString: (NSString *) _iCal @@ -252,7 +237,7 @@ oldApt = nil; } else - oldApt = [self firstEventFromCalendar: [self calendar]]; + oldApt = (iCalEvent *) [self component]; /* compare sequence if requested */ @@ -264,7 +249,7 @@ /* handle new content */ newCalendar = [iCalCalendar parseSingleFromSource: _iCal]; - newApt = [self firstEventFromCalendar: newCalendar]; + newApt = (iCalEvent *) [newCalendar firstChildWithTag: [self componentTag]]; if (newApt == nil) { return [NSException exceptionWithHTTPStatus:400 /* Bad Request */ reason:@"could not parse iCalendar content!"]; @@ -408,7 +393,7 @@ /* load existing content */ - apt = [self event]; + apt = (iCalEvent *) [self component]; /* compare sequence if requested */ @@ -460,7 +445,7 @@ ex = nil; // TODO: do we need to use SOGoAppointment? (prefer iCalEvent?) - apt = [self event]; + apt = (iCalEvent *) [self component]; if (apt) { @@ -520,7 +505,7 @@ else { eventCalendar = [iCalCalendar parseSingleFromSource: contentString]; - event = [self firstEventFromCalendar: eventCalendar]; + event = (iCalEvent *) [eventCalendar firstChildWithTag: [self componentTag]]; organizers = [event childrenWithTag: @"organizer"]; if ([organizers count]) newContentString = contentString; @@ -535,29 +520,6 @@ baseVersion: baseVersion]; } -- (NSString *) roleOfUser: (NSString *) login - inContext: (WOContext *) context -{ - AgenorUserManager *um; - iCalEvent *event; - NSString *role, *email; - - um = [AgenorUserManager sharedUserManager]; - email = [um getEmailForUID: login]; - - event = [self event]; - if ([event isOrganizer: email]) - role = @"Organizer"; - else if ([event isParticipant: email]) - role = @"Participant"; - else if ([[[self container] ownerInContext: nil] isEqualToString: login]) - role = @"SoRole_Owner"; - else - role = nil; - - return role; -} - @end /* SOGoAppointmentObject */ diff --git a/SoObjects/Appointments/SOGoCalendarComponent.h b/SoObjects/Appointments/SOGoCalendarComponent.h index 101ebbb4..50e069ee 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.h +++ b/SoObjects/Appointments/SOGoCalendarComponent.h @@ -36,9 +36,9 @@ iCalCalendar *calendar; } -/* accessors */ - +- (NSString *) componentTag; - (iCalCalendar *) calendar; +- (iCalRepeatableEntityObject *) component; - (NSException *) primarySaveContentString: (NSString *) _iCalString; - (NSException *) primaryDelete; diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index ffae08c1..6ebce383 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -30,6 +30,7 @@ #import #import +#import #import "common.h" @@ -83,6 +84,13 @@ static BOOL sendEMailNotifications = NO; return @"text/calendar"; } +- (NSString *) componentTag +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + - (iCalCalendar *) calendar { NSString *iCalString; @@ -100,6 +108,13 @@ static BOOL sendEMailNotifications = NO; return calendar; } +- (iCalRepeatableEntityObject *) component +{ + return (iCalRepeatableEntityObject *) + [[self calendar] + firstChildWithTag: [self componentTag]]; +} + /* raw saving */ - (NSException *) primarySaveContentString: (NSString *) _iCalString @@ -229,7 +244,7 @@ static BOOL sendEMailNotifications = NO; /* construct message */ headerMap = [NGMutableHashMap hashMapWithCapacity: 5]; - + /* NOTE: multipart/alternative seems like the correct choice but * unfortunately Thunderbird doesn't offer the rich content alternative * at all. Mail.app shows the rich content alternative _only_ @@ -279,4 +294,27 @@ static BOOL sendEMailNotifications = NO; } } +- (NSString *) roleOfUser: (NSString *) login + inContext: (WOContext *) context +{ + AgenorUserManager *um; + iCalRepeatableEntityObject *component; + NSString *role, *email; + + um = [AgenorUserManager sharedUserManager]; + email = [um getEmailForUID: login]; + + component = [self component]; + if ([component isOrganizer: email]) + role = SOGoRole_Organizer; + else if ([component isParticipant: email]) + role = SOGoRole_Participant; + else if ([[[self container] ownerInContext: nil] isEqualToString: login]) + role = SoRole_Owner; + else + role = nil; + + return role; +} + @end diff --git a/SoObjects/Appointments/SOGoTaskObject.h b/SoObjects/Appointments/SOGoTaskObject.h index d0603786..23436263 100644 --- a/SoObjects/Appointments/SOGoTaskObject.h +++ b/SoObjects/Appointments/SOGoTaskObject.h @@ -44,11 +44,6 @@ @interface SOGoTaskObject : SOGoCalendarComponent -/* accessors */ - -- (iCalToDo *) task; -- (iCalToDo *) firstTaskFromCalendar: (iCalCalendar *) calendar; - /* folder management */ - (id)lookupHomeFolderForUID:(NSString *)_uid inContext:(id)_ctx; diff --git a/SoObjects/Appointments/SOGoTaskObject.m b/SoObjects/Appointments/SOGoTaskObject.m index 775dcecf..a70cf10e 100644 --- a/SoObjects/Appointments/SOGoTaskObject.m +++ b/SoObjects/Appointments/SOGoTaskObject.m @@ -58,11 +58,9 @@ static NSString *mailTemplateDefaultLanguage = nil; mailTemplateDefaultLanguage = @"French"; } -/* accessors */ - -- (iCalToDo *) task +- (NSString *) componentTag { - return [self firstTaskFromCalendar: [self calendar]]; + return @"vtodo"; } /* iCal handling */ @@ -206,21 +204,6 @@ static NSString *mailTemplateDefaultLanguage = nil; return allErrors; } -- (iCalToDo *) firstTaskFromCalendar: (iCalCalendar *) aCalendar -{ - iCalToDo *task; - NSArray *tasks; - - tasks = [aCalendar childrenWithTag: @"vtodo"]; - if ([tasks count]) - task = (iCalToDo *) [[tasks objectAtIndex: 0] - groupWithClass: [iCalToDo class]]; - else - task = nil; - - return task; -} - /* "iCal multifolder saves" */ - (NSException *) saveContentString: (NSString *) _iCal @@ -430,7 +413,7 @@ static NSString *mailTemplateDefaultLanguage = nil; /* load existing content */ - task = [self task]; + task = (iCalToDo *) [self component]; /* compare sequence if requested */ @@ -479,7 +462,7 @@ static NSString *mailTemplateDefaultLanguage = nil; NSString *myEMail; // TODO: do we need to use SOGoTask? (prefer iCalToDo?) - task = [self task]; + task = (iCalToDo *) [self component]; if (task == nil) { return [NSException exceptionWithHTTPStatus:500 /* Server Error */ diff --git a/SoObjects/Appointments/product.plist b/SoObjects/Appointments/product.plist index bb2f1a81..a648d70a 100644 --- a/SoObjects/Appointments/product.plist +++ b/SoObjects/Appointments/product.plist @@ -25,13 +25,14 @@ superclass = "SOGoContentObject"; defaultRoles = { "View" = ( "Owner", "Delegate", "Organizer", "Authenticated" ); + "Change Images and Files" = ( "Owner", "Delegate", "Organizer" ); }; }; - SOGoTaskObject = { superclass = "SOGoContentObject"; defaultRoles = { "View" = ( "Owner", "Delegate", "Organizer", "Authenticated" ); + "Change Images and Files" = ( "Owner", "Delegate", "Organizer" ); }; }; SOGoFreeBusyObject = { diff --git a/SoObjects/Mailer/SOGoMailObject.m b/SoObjects/Mailer/SOGoMailObject.m index 4b30424b..10d848cf 100644 --- a/SoObjects/Mailer/SOGoMailObject.m +++ b/SoObjects/Mailer/SOGoMailObject.m @@ -418,7 +418,8 @@ static BOOL debugSoParts = NO; _subtype = [_subtype lowercaseString]; if ([_type isEqualToString:@"text"]) { - if ([_subtype isEqualToString:@"plain"]) + if ([_subtype isEqualToString:@"plain"] + || [_subtype isEqualToString:@"html"]) return YES; if ([_subtype isEqualToString:@"calendar"]) /* we also fetch calendars */ diff --git a/SoObjects/SOGo/SOGoPermissions.h b/SoObjects/SOGo/SOGoPermissions.h index ee196174..5f0e51cc 100644 --- a/SoObjects/SOGo/SOGoPermissions.h +++ b/SoObjects/SOGo/SOGoPermissions.h @@ -36,4 +36,7 @@ extern NSString *SOGoPerm_ReadAcls; extern NSString *SOGoPerm_CreateAndModifyAcls; extern NSString *SOGoPerm_FreeBusyLookup; +extern NSString *SOGoRole_Organizer; +extern NSString *SOGoRole_Participant; + #endif /* SOGOPERMISSIONS_H */ diff --git a/SoObjects/SOGo/SOGoPermissions.m b/SoObjects/SOGo/SOGoPermissions.m index 13e7cb9c..1b856bb2 100644 --- a/SoObjects/SOGo/SOGoPermissions.m +++ b/SoObjects/SOGo/SOGoPermissions.m @@ -34,6 +34,10 @@ NSString *SOGoRole_FreeBusyLookup = @"FreeBusyLookup"; /* for users that have NSString *SOGoRole_FreeBusy = @"FreeBusy"; /* for the "freebusy" special user */ +/* Calendar */ +NSString *SOGoRole_Organizer = @"Organizer"; +NSString *SOGoRole_Participant = @"Participant"; + #warning ReadAcls still not used... NSString *SOGoPerm_ReadAcls = @"ReadAcls"; /* the equivalent of "read-acl" in the WebDAV acls spec, which is diff --git a/UI/MailPartViewers/French.lproj/Localizable.strings b/UI/MailPartViewers/French.lproj/Localizable.strings index d7cacae2..6b90b000 100644 --- a/UI/MailPartViewers/French.lproj/Localizable.strings +++ b/UI/MailPartViewers/French.lproj/Localizable.strings @@ -25,3 +25,5 @@ do_tentative = "tentative"; do_update_status = "mettre l'agenda à jour"; reply_info_no_attendee = "Vous avez reçu une réponse à un événement mais l'expéditeur n'est pas un invité."; reply_info = "Ceci est une réponse à un événement que vous avez organisé."; + +"Size" = "Taille"; diff --git a/UI/MailPartViewers/GNUmakefile b/UI/MailPartViewers/GNUmakefile index 44e1aeed..1850ca57 100644 --- a/UI/MailPartViewers/GNUmakefile +++ b/UI/MailPartViewers/GNUmakefile @@ -18,13 +18,13 @@ MailPartViewers_OBJC_FILES += \ \ UIxMailPartViewer.m \ UIxMailPartTextViewer.m \ + UIxMailPartHTMLViewer.m \ UIxMailPartImageViewer.m \ UIxMailPartLinkViewer.m \ UIxMailPartMixedViewer.m \ UIxMailPartAlternativeViewer.m \ UIxMailPartMessageViewer.m \ UIxMailPartICalViewer.m \ - UIxMailPartHTMLViewer.m \ \ UIxMailPartICalAction.m \ \ diff --git a/UI/MailPartViewers/UIxMailPartAlternativeViewer.m b/UI/MailPartViewers/UIxMailPartAlternativeViewer.m index 95e4e2e7..e7ff28aa 100644 --- a/UI/MailPartViewers/UIxMailPartAlternativeViewer.m +++ b/UI/MailPartViewers/UIxMailPartAlternativeViewer.m @@ -89,10 +89,11 @@ if ((count = [_types count]) == 0) return NSNotFound; - /* we always choose text/plain if available */ + if ((i = [_types indexOfObject:@"text/html"]) != NSNotFound) + return i; if ((i = [_types indexOfObject:@"text/plain"]) != NSNotFound) return i; - + /* then we scan for other text types and choose the first one found */ for (i = 0; i < count; i++) { if ([(NSString *)[_types objectAtIndex:i] hasPrefix:@"text/"]) diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.m b/UI/MailPartViewers/UIxMailPartHTMLViewer.m index ab7746de..4b926e1e 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.m +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.m @@ -1,30 +1,463 @@ -/* - Copyright (C) 2004-2005 SKYRIX Software AG +/* UIxMailPartHTMLViewer.m - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ - This file is part of OpenGroupware.org. +#import +#import +#import +#import +#import +#import +#import +#import - OGo is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. +#import "UIxMailPartHTMLViewer.h" - OGo is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - License for more details. +#define showWhoWeAre() NSLog(@"invoked '%@'", NSStringFromSelector(_cmd)) - You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the - Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. -*/ +@interface _UIxHTMLMailContentHandler : NSObject +{ + NSMutableString *result; + NSMutableString *css; + NSDictionary *attachmentIds; + BOOL inBody; + BOOL inStyle; + BOOL inScript; + BOOL inCSSDeclaration; + NSMutableArray *crumb; +} -#include "UIxMailPartLinkViewer.h" +- (NSString *) result; -@interface UIxMailPartHTMLViewer : UIxMailPartLinkViewer @end -#include "common.h" +@implementation _UIxHTMLMailContentHandler + +- (id) init +{ + if ((self = [super init])) + { + crumb = nil; + css = nil; + result = nil; + attachmentIds = nil; + } + + return self; +} + +- (void) dealloc +{ + if (crumb) + [crumb release]; + if (result) + [result release]; + if (css) + [css release]; + [super dealloc]; +} + +- (void) setAttachmentIds: (NSDictionary *) newAttachmentIds +{ + attachmentIds = newAttachmentIds; +} + +- (NSString *) css +{ + return [[css copy] autorelease]; +} + +- (NSString *) result +{ + return [[result copy] autorelease]; +} + +/* SaxContentHandler */ +- (void) startDocument +{ + if (crumb) + [crumb release]; + if (result) + [result release]; + if (css) + [css release]; + + result = [NSMutableString new]; + css = [NSMutableString new]; + crumb = [NSMutableArray new]; + inBody = NO; + inStyle = NO; + inScript = NO; + inCSSDeclaration = NO; +} + +- (void) endDocument +{ + unsigned int count, max; + + max = [crumb count]; + if (max > 0) + for (count = max - 1; count > -1; count--) + { + [result appendFormat: @"", [crumb objectAtIndex: count]]; + [crumb removeObjectAtIndex: count]; + } +} + +- (void) startPrefixMapping: (NSString *)_prefix + uri: (NSString *)_uri +{ + showWhoWeAre(); +} + +- (void) endPrefixMapping: (NSString *)_prefix +{ + showWhoWeAre(); +} + +- (NSString *) _valueForCSSIdentifier: (NSString *) primaryValue +{ + NSMutableString *value; + NSEnumerator *classes; + NSString *currentValue; + + value = [NSMutableString new]; + [value autorelease]; + + classes = [[primaryValue componentsSeparatedByString: @" "] objectEnumerator]; + currentValue = [classes nextObject]; + while (currentValue) + { + [value appendFormat: @"SOGoHTMLMail-%@ ", currentValue]; + currentValue = [classes nextObject]; + } + + return value; +} + +- (void) _appendStyle: (unichar *) _chars + length: (int) _len +{ + unsigned int count; + unichar *start, *currentChar; + + start = _chars; + currentChar = start; + for (count = 0; count < _len; count++) + { + currentChar = _chars + count; + if (inCSSDeclaration) + { + if (*(char *) currentChar == '}') + inCSSDeclaration = NO; + } + else + { + if (*(char *) currentChar == '{') + inCSSDeclaration = YES; + else if (*(char *) currentChar == '.' + || *(char *) currentChar == '#') + { + [css appendString: [NSString stringWithCharacters: start + length: (currentChar - start + 1)]]; + [css appendString: @"SOGoHTMLMail-"]; + start = currentChar + 1; + } + } + } + [css appendString: [NSString stringWithCharacters: start + length: (currentChar - start + 1)]]; +} + +- (void) startElement: (NSString *) _localName + namespace: (NSString *) _ns + rawName: (NSString *) _rawName + attributes: (id ) _attributes +{ + unsigned int count, max; + NSString *name, *value; + NSMutableString *resultPart; + BOOL skipAttribute; + + if (inStyle || inScript) + ; + else if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame) + inBody = YES; + else if ([_localName caseInsensitiveCompare: @"script"] == NSOrderedSame) + inScript = YES; + else if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame) + inStyle = YES; + else if (inBody) + { + resultPart = [NSMutableString new]; + [resultPart appendFormat: @"<%@", _rawName]; + + max = [_attributes count]; + for (count = 0; count < max; count++) + { + skipAttribute = NO; + name = [_attributes nameAtIndex: count]; + if ([name caseInsensitiveCompare: @"class"] == NSOrderedSame + || [name caseInsensitiveCompare: @"id"] == NSOrderedSame) + value = [self _valueForCSSIdentifier: [_attributes valueAtIndex: count]]; + else if ([[name lowercaseString] hasPrefix: @"on"]) + skipAttribute = YES; + else if ([name caseInsensitiveCompare: @"src"] == NSOrderedSame) + { + value = [_attributes valueAtIndex: count]; + if ([value hasPrefix: @"cid:"]) + { + value = [attachmentIds + objectForKey: [value substringFromIndex: 4]]; + skipAttribute = (value == nil); + } + else + skipAttribute = YES; + } + else + value = [_attributes valueAtIndex: count]; + if (!skipAttribute) + [resultPart appendFormat: @" %@=\"%@\"", + name, [value stringByReplacingString: @"\"" + withString: @"\\\""]]; + } + + [resultPart appendString: @">"]; + [result appendString: resultPart]; + } +} + +- (void) endElement: (NSString *) _localName + namespace: (NSString *) _ns + rawName: (NSString *) _rawName +{ + if (inStyle) + { + if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame) + { + inStyle = NO; + inCSSDeclaration = NO; + } + } + else if (inScript) + inScript = ([_localName caseInsensitiveCompare: @"script"] != NSOrderedSame); + else if (inBody) + { + if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame) + inBody = NO; + else + [result appendFormat: @"", _localName]; + } +} + +- (void) characters: (unichar *) _chars + length: (int) _len +{ + NSString *tmpString; + + if (!inScript) + { + if (inStyle) + [self _appendStyle: _chars length: _len]; + if (inBody) + { + tmpString = [NSString stringWithCharacters: _chars length: _len]; + [result appendString: [tmpString stringByEscapingHTMLString]]; + } + } +} + +- (void) ignorableWhitespace: (unichar *) _chars + length: (int) _len +{ + showWhoWeAre(); +} + +- (void) processingInstruction: (NSString *) _pi + data: (NSString *) _data +{ + showWhoWeAre(); +} + +- (void) setDocumentLocator: (id ) _locator +{ + showWhoWeAre(); +} + +- (void) skippedEntity: (NSString *) _entityName +{ + showWhoWeAre(); +} + +/* SaxLexicalHandler */ +- (void) comment: (unichar *) _chars + length: (int) _len +{ + if (inStyle) + [self _appendStyle: _chars length: _len]; +} + +- (void) startDTD: (NSString *) _name + publicId: (NSString *) _pub + systemId: (NSString *) _sys +{ + showWhoWeAre(); +} + +- (void) endDTD +{ + showWhoWeAre(); +} + +- (void) startEntity: (NSString *) _name +{ + showWhoWeAre(); +} + +- (void) endEntity: (NSString *) _name +{ + showWhoWeAre(); +} + +- (void) startCDATA +{ + showWhoWeAre(); +} + +- (void) endCDATA +{ + showWhoWeAre(); +} + +@end + +@interface NSDictionary (SOGoDebug) + +- (void) dump; + +@end + +@implementation NSDictionary (SOGoDebug) + +- (void) dump +{ + NSEnumerator *keys; + NSString *key; + NSMutableString *dump; + + dump = [NSMutableString new]; + [dump appendFormat: @"\nNSDictionary dump (%@):\n", self]; + keys = [[self allKeys] objectEnumerator]; + key = [keys nextObject]; + while (key) + { + [dump appendFormat: @"%@: %@\n", key, [self objectForKey: key]]; + key = [keys nextObject]; + } + [dump appendFormat: @"--- end ---\n"]; + + NSLog (dump); + [dump release]; +} + +@end @implementation UIxMailPartHTMLViewer -@end /* UIxMailPartHTMLViewer */ + +- (void) _convertReferencesForPart: (NSDictionary *) part + withCount: (unsigned int) count + andBaseURL: (NSString *) url + intoDictionary: (NSMutableDictionary *) attachmentIds +{ + NSString *bodyId; + + bodyId = [part objectForKey: @"bodyId"]; + if ([bodyId length] > 0) + { + NSLog(@"%@", part); + if ([bodyId hasPrefix: @"<"]) + bodyId = [bodyId substringFromIndex: 1]; + if ([bodyId hasSuffix: @">"]) + bodyId = [bodyId substringToIndex: [bodyId length] - 1]; + [attachmentIds setObject: [url stringByAppendingFormat: @"/%d", count] + forKey: bodyId]; + } +} + +- (NSDictionary *) _attachmentIds +{ + NSMutableDictionary *attachmentIds; + UIxMailPartViewer *parent; + unsigned int count, max; + NSString *baseURL; + NSArray *parts; + + attachmentIds = [NSMutableDictionary new]; + [attachmentIds autorelease]; + + parent = [self parent]; + if ([NSStringFromClass ([parent class]) + isEqualToString: @"UIxMailPartAlternativeViewer"]) + { + baseURL = [[self clientObject] baseURLInContext: context]; + parts = [[parent bodyInfo] objectForKey: @"parts"]; + max = [parts count]; + for (count = 0; count < max; count++) + [self _convertReferencesForPart: [parts objectAtIndex: count] + withCount: count + 1 + andBaseURL: baseURL + intoDictionary: attachmentIds]; + } + + NSLog(@"attc: '%@'", attachmentIds); + return attachmentIds; +} + +- (NSString *) flatContentAsString +{ + id parser; + _UIxHTMLMailContentHandler *handler; + NSString *preparsedContent, *content, *css; + + preparsedContent = [super flatContentAsString]; + parser = [[SaxXMLReaderFactory standardXMLReaderFactory] + createXMLReaderForMimeType: @"text/html"]; + + handler = [_UIxHTMLMailContentHandler new]; + [handler setAttachmentIds: [self _attachmentIds]]; + [parser setContentHandler: handler]; + [parser setProperty: @"http://xml.org/sax/properties/lexical-handler" + to: handler]; + [parser parseFromSource: preparsedContent]; + + css = [handler css]; + if ([css length]) + content + = [NSString stringWithFormat: @"%@", + css, [handler result]]; + else + content = [handler result]; + [handler release]; + + return content; +} + +@end diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m index 365d144e..7af72391 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.m +++ b/UI/MailPartViewers/UIxMailPartICalViewer.m @@ -212,7 +212,7 @@ } - (iCalEvent *)storedEvent { - return [(SOGoAppointmentObject *)[self storedEventObject] event]; + return (iCalEvent *) [(SOGoAppointmentObject *)[self storedEventObject] component]; } /* organizer tracking */ diff --git a/UI/MailPartViewers/UIxMailPartViewer.m b/UI/MailPartViewers/UIxMailPartViewer.m index 72ca9452..bb988c40 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.m +++ b/UI/MailPartViewers/UIxMailPartViewer.m @@ -122,17 +122,17 @@ } charset = [(NSDictionary *) - [(NSDictionary *)[self bodyInfo] objectForKey:@"parameterList"] - objectForKey:@"charset"]; + [(NSDictionary *)[self bodyInfo] objectForKey:@"parameterList"] + objectForKey:@"charset"]; charset = [charset lowercaseString]; - + // TODO: properly decode charset, might need to handle encoding? if ([charset length] > 0) { - s = [NSString stringWithData:content usingEncodingNamed:charset]; + s = [NSString stringWithData: content usingEncodingNamed: charset]; } else { - s = [[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding]; + s = [[NSString alloc] initWithData: content encoding: NSUTF8StringEncoding]; s = [s autorelease]; } diff --git a/UI/MailPartViewers/UIxMailRenderingContext.m b/UI/MailPartViewers/UIxMailRenderingContext.m index a743983f..e2a101ae 100644 --- a/UI/MailPartViewers/UIxMailRenderingContext.m +++ b/UI/MailPartViewers/UIxMailRenderingContext.m @@ -178,9 +178,10 @@ static BOOL showNamedTextAttachmentsInline = NO; if ([mt isEqualToString:@"multipart"]) { if ([st isEqualToString:@"mixed"]) return [self mixedViewer]; - if ([st isEqualToString:@"signed"]) + else if ([st isEqualToString:@"signed"]) return [self signedViewer]; - if ([st isEqualToString:@"alternative"]) + else if ([st isEqualToString:@"alternative"] + || [st isEqualToString:@"related"]) return [self alternativeViewer]; if ([st isEqualToString:@"report"]) diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index f8b19473..5c2d39c7 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -264,11 +264,9 @@ { iCalCalendar *calendar; iCalEvent *appointment; - SOGoAppointmentObject *clientObject; - clientObject = [self clientObject]; calendar = [iCalCalendar parseSingleFromSource: _iCalString]; - appointment = [clientObject firstEventFromCalendar: calendar]; + appointment = (iCalEvent *) [calendar firstChildWithTag: @"vevent"]; return appointment; } diff --git a/UI/Scheduler/UIxAppointmentView.m b/UI/Scheduler/UIxAppointmentView.m index cb4562ab..14b3b6ea 100644 --- a/UI/Scheduler/UIxAppointmentView.m +++ b/UI/Scheduler/UIxAppointmentView.m @@ -162,25 +162,14 @@ - (iCalEvent *) appointment { - NSString *iCalString; - iCalCalendar *calendar; SOGoAppointmentObject *clientObject; - - if (appointment != nil) - return appointment; - - clientObject = [self clientObject]; - - iCalString = [[self clientObject] valueForKey:@"iCalString"]; - if (![iCalString isNotNull] || [iCalString length] == 0) { - [self errorWithFormat:@"(%s): missing iCal string!", - __PRETTY_FUNCTION__]; - return nil; - } - calendar = [iCalCalendar parseSingleFromSource: iCalString]; - appointment = [clientObject firstEventFromCalendar: calendar]; - [appointment retain]; + if (!appointment) + { + clientObject = [self clientObject]; + appointment = (iCalEvent *) [clientObject component]; + [appointment retain]; + } return appointment; } diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 2b958f1a..e23e664a 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -848,23 +848,13 @@ { NSString *filename; iCalEntityObject *calObject; - id co; + SOGoCalendarComponent *co; if (componentLoaded) { co = [self clientObject]; - if ([co isKindOfClass: [SOGoAppointmentObject class]]) - { - calObject = (iCalEntityObject *) [co event]; - filename = [self _toolbarForCalObject: calObject]; - } - else if ([co isKindOfClass: [SOGoTaskObject class]]) - { - calObject = (iCalEntityObject *) [co task]; - filename = [self _toolbarForCalObject: calObject]; - } - else - filename = @""; + calObject = [co component]; + filename = [self _toolbarForCalObject: calObject]; } else filename = @""; diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index 9335c23a..8ff0ff6e 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -250,11 +250,9 @@ { iCalCalendar *calendar; iCalToDo *task; - SOGoTaskObject *clientObject; - clientObject = [self clientObject]; calendar = [iCalCalendar parseSingleFromSource: _iCalString]; - task = [clientObject firstTaskFromCalendar: calendar]; + task = (iCalToDo *) [calendar firstChildWithTag: @"vtodo"]; return task; } @@ -406,7 +404,7 @@ newStatus = [[self queryParameterForKey: @"status"] intValue]; taskObject = [self clientObject]; - task = [taskObject task]; + task = (iCalToDo *) [taskObject component]; switch (newStatus) { case 1: diff --git a/UI/Scheduler/UIxTaskView.m b/UI/Scheduler/UIxTaskView.m index 71bf79c8..0f31e924 100644 --- a/UI/Scheduler/UIxTaskView.m +++ b/UI/Scheduler/UIxTaskView.m @@ -162,25 +162,14 @@ - (iCalToDo *) task { - NSString *iCalString; - iCalCalendar *calendar; SOGoTaskObject *clientObject; - - if (task != nil) - return task; - - clientObject = [self clientObject]; - - iCalString = [[self clientObject] valueForKey:@"iCalString"]; - if (![iCalString isNotNull] || [iCalString length] == 0) { - [self errorWithFormat:@"(%s): missing iCal string!", - __PRETTY_FUNCTION__]; - return nil; - } - calendar = [iCalCalendar parseSingleFromSource: iCalString]; - task = [clientObject firstTaskFromCalendar: calendar]; - [task retain]; + if (!task) + { + clientObject = [self clientObject]; + task = (iCalToDo *) [clientObject component]; + [task retain]; + } return task; } diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index e9f0cf4c..f08d54d5 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -190,11 +190,11 @@ actionName = "delete"; }; edit = { - protectedBy = "Change Images and Files"; + protectedBy = "View"; pageName = "UIxTaskEditor"; }; editAsTask = { - protectedBy = "Change Images and Files"; + protectedBy = "View"; pageName = "UIxTaskEditor"; }; save = { diff --git a/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox b/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox index 8ca1d5f7..bafb0547 100644 --- a/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox +++ b/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox @@ -1,23 +1,9 @@ -
- - - -
- -
- : - / - , - - : - -
-
-
+
diff --git a/UI/WebServerResources/MailerUI.css b/UI/WebServerResources/MailerUI.css index 1997ee89..f10b370a 100644 --- a/UI/WebServerResources/MailerUI.css +++ b/UI/WebServerResources/MailerUI.css @@ -72,6 +72,13 @@ DIV#messageContent background: #fff; } +DIV#messageContent P IMG +{ + border: 0px; + vertical-align: middle; + margin-right: 1em; +} + DIV#folderTreeContent { position: absolute; @@ -84,18 +91,6 @@ DIV#folderTreeContent border: 1px solid #fff; } -DIV#messageContent P -{ - line-height: 3em; -} - -DIV#messageContent P IMG -{ - border: 0px; - vertical-align: middle; - margin-right: 1em; -} - .aptview_title { color: #000000; @@ -378,6 +373,23 @@ DIV.mailer_plaincontent padding: 0px; } +DIV.mailer_plaincontent P +{ + line-height: 3em; + height: auto; + margin: 0px; + padding: 0px; +} + +DIV.mailer_htmlcontent P +{ + white-space: normal; + font-family: serif; + font-size: inherit; + margin: 0px; + padding: 0px; +} + /* attachment editor */ form#attachment_form -- 2.39.5