+2007-02-15 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * 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 <wsourdeau@inverse.ca>
* UI/Scheduler/UIxCalMulticolumnDayView.[hm]: new daily view
- (void) addChildren: (NSArray *) someChildren;
- (NSArray *) children;
+- (CardElement *) firstChildWithTag: (NSString *) aTag;
- (NSArray *) childrenWithTag: (NSString *) aTag;
- (NSArray *) childrenWithAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue;
types: (NSArray *) someTypes
singleValue: (NSString *) aValue;
-
- (CardGroup *) groupWithClass: (Class) groupClass;
- (void) setChildrenAsCopy: (NSMutableArray *) someChildren;
[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;
+2007-02-15 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * CardGroup.m ([CardGroup -firstChildWithTag:aTag]): new method.
+
2007-02-09 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* CardGroup.m ([CardGroup +cardParser]): find the correct parser
@interface SOGoAppointmentObject : SOGoCalendarComponent
-/* accessors */
-
-- (iCalEvent *) event;
-- (iCalEvent *) firstEventFromCalendar: (iCalCalendar *) calendar;
-
/* folder management */
- (id) lookupHomeFolderForUID: (NSString *) _uid inContext: (id)_ctx;
#import <SOGo/AgenorUserManager.h>
#import <SOGo/SOGoObject.h>
+#import <SOGo/SOGoPermissions.h>
#import "iCalEntityObject+Agenor.h"
@implementation SOGoAppointmentObject
-/* accessors */
-
-- (iCalEvent *) event
+- (NSString *) componentTag
{
- return [self firstEventFromCalendar: [self calendar]];
+ return @"vevent";
}
/* iCal handling */
/* 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;
}
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
oldApt = nil;
}
else
- oldApt = [self firstEventFromCalendar: [self calendar]];
+ oldApt = (iCalEvent *) [self component];
/* compare sequence if requested */
/* 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!"];
/* load existing content */
- apt = [self event];
+ apt = (iCalEvent *) [self component];
/* compare sequence if requested */
ex = nil;
// TODO: do we need to use SOGoAppointment? (prefer iCalEvent?)
- apt = [self event];
+ apt = (iCalEvent *) [self component];
if (apt)
{
else
{
eventCalendar = [iCalCalendar parseSingleFromSource: contentString];
- event = [self firstEventFromCalendar: eventCalendar];
+ event = (iCalEvent *) [eventCalendar firstChildWithTag: [self componentTag]];
organizers = [event childrenWithTag: @"organizer"];
if ([organizers count])
newContentString = contentString;
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 */
iCalCalendar *calendar;
}
-/* accessors */
-
+- (NSString *) componentTag;
- (iCalCalendar *) calendar;
+- (iCalRepeatableEntityObject *) component;
- (NSException *) primarySaveContentString: (NSString *) _iCalString;
- (NSException *) primaryDelete;
#import <NGMail/NGSendMail.h>
#import <SOGo/AgenorUserManager.h>
+#import <SOGo/SOGoPermissions.h>
#import "common.h"
return @"text/calendar";
}
+- (NSString *) componentTag
+{
+ [self subclassResponsibility: _cmd];
+
+ return nil;
+}
+
- (iCalCalendar *) calendar
{
NSString *iCalString;
return calendar;
}
+- (iCalRepeatableEntityObject *) component
+{
+ return (iCalRepeatableEntityObject *)
+ [[self calendar]
+ firstChildWithTag: [self componentTag]];
+}
+
/* raw saving */
- (NSException *) primarySaveContentString: (NSString *) _iCalString
/* 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_
}
}
+- (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
@interface SOGoTaskObject : SOGoCalendarComponent
-/* accessors */
-
-- (iCalToDo *) task;
-- (iCalToDo *) firstTaskFromCalendar: (iCalCalendar *) calendar;
-
/* folder management */
- (id)lookupHomeFolderForUID:(NSString *)_uid inContext:(id)_ctx;
mailTemplateDefaultLanguage = @"French";
}
-/* accessors */
-
-- (iCalToDo *) task
+- (NSString *) componentTag
{
- return [self firstTaskFromCalendar: [self calendar]];
+ return @"vtodo";
}
/* iCal handling */
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
/* load existing content */
- task = [self task];
+ task = (iCalToDo *) [self component];
/* compare sequence if requested */
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 */
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 = {
_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 */
extern NSString *SOGoPerm_CreateAndModifyAcls;
extern NSString *SOGoPerm_FreeBusyLookup;
+extern NSString *SOGoRole_Organizer;
+extern NSString *SOGoRole_Participant;
+
#endif /* SOGOPERMISSIONS_H */
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
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";
\
UIxMailPartViewer.m \
UIxMailPartTextViewer.m \
+ UIxMailPartHTMLViewer.m \
UIxMailPartImageViewer.m \
UIxMailPartLinkViewer.m \
UIxMailPartMixedViewer.m \
UIxMailPartAlternativeViewer.m \
UIxMailPartMessageViewer.m \
UIxMailPartICalViewer.m \
- UIxMailPartHTMLViewer.m \
\
UIxMailPartICalAction.m \
\
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/"])
-/*
- Copyright (C) 2004-2005 SKYRIX Software AG
+/* UIxMailPartHTMLViewer.m - this file is part of SOGo
+ *
+ * Copyright (C) 2007 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * 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 <Foundation/NSArray.h>
+#import <SaxObjC/SaxAttributes.h>
+#import <SaxObjC/SaxContentHandler.h>
+#import <SaxObjC/SaxLexicalHandler.h>
+#import <SaxObjC/SaxXMLReader.h>
+#import <SaxObjC/SaxXMLReaderFactory.h>
+#import <NGExtensions/NSString+misc.h>
+#import <NGObjWeb/SoObjects.h>
- 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 <SaxContentHandler, SaxLexicalHandler>
+{
+ 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 <SaxAttributes>) _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 <NSObject, SaxLocator>) _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 <NSObject, SaxXMLReader> 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: @"<style type=\"text/css\">%@</style>%@",
+ css, [handler result]];
+ else
+ content = [handler result];
+ [handler release];
+
+ return content;
+}
+
+@end
}
- (iCalEvent *)storedEvent {
- return [(SOGoAppointmentObject *)[self storedEventObject] event];
+ return (iCalEvent *) [(SOGoAppointmentObject *)[self storedEventObject] component];
}
/* organizer tracking */
}
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];
}
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"])
{
iCalCalendar *calendar;
iCalEvent *appointment;
- SOGoAppointmentObject *clientObject;
- clientObject = [self clientObject];
calendar = [iCalCalendar parseSingleFromSource: _iCalString];
- appointment = [clientObject firstEventFromCalendar: calendar];
+ appointment = (iCalEvent *) [calendar firstChildWithTag: @"vevent"];
return appointment;
}
- (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;
}
{
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 = @"";
{
iCalCalendar *calendar;
iCalToDo *task;
- SOGoTaskObject *clientObject;
- clientObject = [self clientObject];
calendar = [iCalCalendar parseSingleFromSource: _iCalString];
- task = [clientObject firstTaskFromCalendar: calendar];
+ task = (iCalToDo *) [calendar firstChildWithTag: @"vtodo"];
return task;
}
newStatus = [[self queryParameterForKey: @"status"] intValue];
taskObject = [self clientObject];
- task = [taskObject task];
+ task = (iCalToDo *) [taskObject component];
switch (newStatus)
{
case 1:
- (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;
}
actionName = "delete";
};
edit = {
- protectedBy = "Change Images and Files";
+ protectedBy = "View";
pageName = "UIxTaskEditor";
};
editAsTask = {
- protectedBy = "Change Images and Files";
+ protectedBy = "View";
pageName = "UIxTaskEditor";
};
save = {
<?xml version="1.0" standalone="yes"?>
-<div xmlns="http://www.w3.org/1999/xhtml"
- xmlns:var="http://www.skyrix.com/od/binding"
- xmlns:label="OGo:label"
- class="linked_attachment_frame"
->
- <!-- TODO: make an optional iframe -->
- <!-- TODO: add a server side 'safe' renderer -->
-
- <div class="linked_attachment_body">
- <a var:href="pathToAttachment"
- var:title="filenameForDisplay"
- ><var:string value="filenameForDisplay" /></a>
- <div class="linked_attachment_meta">
- <var:string label:value="Type" />:
- <var:string value="bodyInfo.type" /> /
- <var:string value="bodyInfo.subtype" />,
-
- <var:string label:value="Size" />:
- <var:string value="bodyInfo.size" formatter="sizeFormatter" />
- </div>
- </div>
-</div>
+<div
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label"
+ class="mailer_htmlcontent"
+><var:string value="flatContentAsString" const:escapeHTML="NO" /></div>
background: #fff;
}
+DIV#messageContent P IMG
+{
+ border: 0px;
+ vertical-align: middle;
+ margin-right: 1em;
+}
+
DIV#folderTreeContent
{
position: absolute;
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;
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