diff --git a/ChangeLog b/ChangeLog index e801e342c..23897185f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2010-06-04 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoAppointmentFolderXML.[hm]: same as + below for XML. + + * SoObjects/Appointments/SOGoAppointmentFolderICS.[hm]: new class + module that exports personal calendars as one ICS file. + + * SoObjects/Appointments/SOGoAppointmentFolders.m + (-folderObjectKeys): new method that return the "toOne..." keys + mapping XML or ICS representation of calendars. + 2010-06-03 Ludovic Marcotte * Added Ukrainian translation (first pass) from diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index 20ec67b1f..01a0a820c 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,11 @@ +2010-06-04 Wolfgang Sourdeau + + * iCalXMLRenderer.m: new class module for exporting iCalCalendar + objects as XML files. + + * iCalUTCOffset.m: new class module for handling of the + "tzoffsetfrom" and "tzoffsetto" elements. + 2010-05-05 Wolfgang Sourdeau * iCalPerson.m (-setParticipationStatus:, -participationStatus): diff --git a/SOPE/NGCards/GNUmakefile b/SOPE/NGCards/GNUmakefile index e35b4f71a..3691f5fff 100644 --- a/SOPE/NGCards/GNUmakefile +++ b/SOPE/NGCards/GNUmakefile @@ -26,7 +26,9 @@ libNGCards_HEADER_FILES = \ \ CardElement.h \ CardGroup.h \ + \ CardVersitRenderer.h \ + iCalXMLRenderer.h \ \ NGCards.h \ iCalAlarm.h \ @@ -49,6 +51,7 @@ libNGCards_HEADER_FILES = \ iCalTimeZonePeriod.h \ iCalToDo.h \ iCalTrigger.h \ + iCalUTCOffset.h \ \ NSCalendarDate+ICal.h \ \ @@ -75,7 +78,9 @@ libNGCards_OBJC_FILES = \ \ CardElement.m \ CardGroup.m \ + \ CardVersitRenderer.m \ + iCalXMLRenderer.m \ \ iCalAlarm.m \ iCalAttachment.m \ @@ -99,6 +104,7 @@ libNGCards_OBJC_FILES = \ iCalTimeZonePeriod.m \ iCalToDo.m \ iCalTrigger.m \ + iCalUTCOffset.m \ iCalWeeklyRecurrenceCalculator.m\ iCalYearlyRecurrenceCalculator.m\ \ diff --git a/SOPE/NGCards/iCalTimeZonePeriod.m b/SOPE/NGCards/iCalTimeZonePeriod.m index f36ef8efb..ad46e3545 100644 --- a/SOPE/NGCards/iCalTimeZonePeriod.m +++ b/SOPE/NGCards/iCalTimeZonePeriod.m @@ -27,6 +27,7 @@ #import "iCalDateTime.h" #import "iCalRecurrenceRule.h" #import "iCalByDayMask.h" +#import "iCalUTCOffset.h" #import "iCalTimeZonePeriod.h" @@ -40,9 +41,10 @@ tagClass = [iCalRecurrenceRule class]; else if ([classTag isEqualToString: @"DTSTART"]) tagClass = [iCalDateTime class]; - else if ([classTag isEqualToString: @"TZNAME"] - || [classTag isEqualToString: @"TZOFFSETFROM"] + else if ([classTag isEqualToString: @"TZOFFSETFROM"] || [classTag isEqualToString: @"TZOFFSETTO"]) + tagClass = [iCalUTCOffset class]; + else if ([classTag isEqualToString: @"TZNAME"]) tagClass = [CardElement class]; else tagClass = [super classForTag: classTag]; diff --git a/SOPE/NGCards/iCalUTCOffset.h b/SOPE/NGCards/iCalUTCOffset.h new file mode 100644 index 000000000..d6d4c4fc8 --- /dev/null +++ b/SOPE/NGCards/iCalUTCOffset.h @@ -0,0 +1,31 @@ +/* iCalUTCOffset.h - this file is part of SOPE + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#ifndef ICALUTCOFFSET_H +#define ICALUTCOFFSET_H + +#import "CardElement.h" + +@interface iCalUTCOffset : CardElement +@end + +#endif /* ICALUTCOFFSET_H */ diff --git a/SOPE/NGCards/iCalUTCOffset.m b/SOPE/NGCards/iCalUTCOffset.m new file mode 100644 index 000000000..703e3e396 --- /dev/null +++ b/SOPE/NGCards/iCalUTCOffset.m @@ -0,0 +1,27 @@ +/* iCalUTCOffset.m - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#import "iCalUTCOffset.h" + +@implementation iCalUTCOffset + +@end diff --git a/SOPE/NGCards/iCalXMLRenderer.h b/SOPE/NGCards/iCalXMLRenderer.h new file mode 100644 index 000000000..c19ac4f29 --- /dev/null +++ b/SOPE/NGCards/iCalXMLRenderer.h @@ -0,0 +1,41 @@ +/* iCalXMLRenderer.h - this file is part of SOPE + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#ifndef ICALXMLRENDERER_H +#define ICALXMLRENDERER_H + +#import + +@class NSMutableString; +@class NSString; + +@class iCalCalendar; + +@interface iCalXMLRenderer : NSObject + ++ (iCalXMLRenderer *) sharedXMLRenderer; + +- (NSString *) render: (iCalCalendar *) calendar; + +@end + +#endif /* ICALXMLRENDERER_H */ diff --git a/SOPE/NGCards/iCalXMLRenderer.m b/SOPE/NGCards/iCalXMLRenderer.m new file mode 100644 index 000000000..50fa9436a --- /dev/null +++ b/SOPE/NGCards/iCalXMLRenderer.m @@ -0,0 +1,438 @@ +/* iCalXMLRenderer.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse inc. + * + * 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 class implements most of the XML iCalendar spec as defined here: + http://tools.ietf.org/html/draft-daboo-et-al-icalendar-in-xml-04 */ + +#import +#import +#import +#import + +#import +#import + +#import "CardElement.h" +#import "CardGroup.h" +#import "iCalDateTime.h" +#import "iCalPerson.h" +#import "iCalRecurrenceRule.h" +#import "iCalUTCOffset.h" + +#import "iCalXMLRenderer.h" + +@interface CardElement (iCalXMLExtension) + +- (NSString *) xmlRender; + +@end + +@interface iCalXMLRenderer (PrivateAPI) + +- (NSString *) renderElement: (CardElement *) anElement; +- (NSString *) renderGroup: (CardGroup *) aGroup; + +@end + +@implementation iCalXMLRenderer + ++ (iCalXMLRenderer *) sharedXMLRenderer +{ + static iCalXMLRenderer *sharedXMLRenderer = nil; + + if (!sharedXMLRenderer) + sharedXMLRenderer = [self new]; + + return sharedXMLRenderer; +} + +- (NSString *) render: (iCalCalendar *) calendar +{ + return [NSString stringWithFormat: + @"\n" + @"" + @"%@" + @"", + [calendar xmlRender]]; +} + +@end + +@implementation CardElement (iCalXMLExtension) + +- (NSString *) xmlValueTag +{ + return @"text"; +} + +- (NSString *) xmlParameterTag: (NSString *) paramName +{ + return nil; +} + +- (void) _appendPaddingValues: (int) max + withTag: (NSString *) valueTag + intoString: (NSMutableString *) rendering +{ + int count; + + for (count = 0; count < max; count++) + [rendering appendFormat: @"<%@/>"]; +} + +- (NSString *) _xmlRenderParameter: (NSString *) paramName +{ + NSMutableString *rendering; + NSArray *paramValues; + NSString *lowerName, *paramTypeTag, *escapedValue; + int count, max; + + paramValues = [attributes objectForKey: paramName]; + max = [paramValues count]; + if (max > 0) + { + lowerName = [paramName lowercaseString]; + rendering = [NSMutableString stringWithCapacity: 32]; + paramTypeTag = [self xmlParameterTag: [paramName lowercaseString]]; + for (count = 0; count < max; count++) + { + [rendering appendFormat: @"<%@>", lowerName]; + if (paramTypeTag) + [rendering appendFormat: @"<%@>", paramTypeTag]; + escapedValue = [[paramValues objectAtIndex: count] + stringByEscapingXMLString]; + [rendering appendFormat: @"%@", escapedValue]; + if (paramTypeTag) + [rendering appendFormat: @"", paramTypeTag]; + [rendering appendFormat: @"", lowerName]; + } + } + else + rendering = nil; + + return rendering; +} + +- (NSString *) _xmlRenderParameters +{ + NSArray *keys; + NSMutableArray *renderedValues; + NSMutableString *rendering; + NSString *currentValue; + int count, max; + BOOL displayed; + + keys = [attributes allKeys]; + max = [keys count]; + if (max > 0) + { + rendering = [NSMutableString stringWithCapacity: 64]; + renderedValues = [NSMutableArray arrayWithCapacity: max]; + displayed = NO; + for (count = 0; count < max; count++) + { + currentValue + = [self _xmlRenderParameter: [keys objectAtIndex: count]]; + if ([currentValue length] > 0) + [rendering appendString: currentValue]; + } + } + else + rendering = nil; + + return rendering; +} + +- (NSString *) _xmlRenderValue +{ + NSMutableString *rendering; + NSString *valueTag, *currentValue; + int count, max; + BOOL displayed; + + valueTag = [self xmlValueTag]; + rendering = [NSMutableString stringWithCapacity: 64]; + max = [values count]; + displayed = NO; + for (count = 0; count < max; count++) + { + currentValue = [[values objectAtIndex: count] + stringByEscapingXMLString]; + if ([currentValue length] > 0) + { + if (!displayed) + { + [self _appendPaddingValues: count withTag: valueTag + intoString: rendering]; + displayed = YES; + } + [rendering appendFormat: @"<%@>%@", + valueTag, currentValue, valueTag]; + } + } + + return rendering; +} + +- (NSString *) xmlRender +{ + NSMutableString *rendering; + NSString *lowerTag, *rParameters, *value; + + rParameters = [self _xmlRenderParameters]; + value = [self _xmlRenderValue]; + if ([value length]) + { + rendering = [NSMutableString stringWithCapacity: 128]; + lowerTag = [tag lowercaseString]; + [rendering appendFormat: @"<%@>", lowerTag]; + if ([rParameters length] > 0) + [rendering appendFormat: @"%@", + rParameters]; + [rendering appendString: value]; + [rendering appendFormat: @"", lowerTag]; + } + else + rendering = nil; + + return rendering; +} + +@end + +@implementation iCalDateTime (iCalXMLExtension) + +- (NSString *) xmlValueTag +{ + return ([self isAllDay] ? @"date" : @"date-time"); +} + +@end + +@implementation iCalPerson (iCalXMLExtension) + +- (NSString *) xmlParameterTag: (NSString *) paramName +{ + NSString *paramTag; + + if ([paramName isEqualToString: @"delegated-from"] + || [paramName isEqualToString: @"delegated-to"] + || [paramName isEqualToString: @"sent-by"]) + paramTag = @"cal-address"; + else + paramTag = [super xmlParameterTag: paramName]; + + return paramTag; +} + +- (NSString *) xmlValueTag +{ + return @"cal-address"; +} + +@end + +@implementation iCalRecurrenceRule (iCalXMLExtension) + +- (NSString *) _xmlRenderValue +{ + NSMutableString *rendering; + NSArray *valueParts; + NSString *valueTag, *currentValue; + int count, max; + + max = [values count]; + rendering = [NSMutableString stringWithCapacity: 64]; + for (count = 0; count < max; count++) + { + currentValue = [[values objectAtIndex: count] + stringByEscapingXMLString]; + if ([currentValue length] > 0) + { + valueParts = [currentValue componentsSeparatedByString: @"="]; + if ([valueParts count] == 2) + { + valueTag = [[valueParts objectAtIndex: 0] lowercaseString]; + [rendering appendFormat: @"<%@>%@", + valueTag, + [valueParts objectAtIndex: 1], + valueTag]; + } + } + } + + return rendering; +} + +@end + +@implementation iCalUTCOffset (iCalXMLExtension) + +- (NSString *) xmlValueTag +{ + return @"utc-offset"; +} + +@end + +@implementation CardGroup (iCalXMLExtension) + +- (NSString *) xmlRender +{ + NSString *lowerTag; + int count, max; + NSMutableString *rendering; + NSMutableArray *properties, *components; + CardElement *currentChild; + + rendering = [NSMutableString stringWithCapacity: 4096]; + max = [children count]; + if (max > 0) + { + properties = [[NSMutableArray alloc] initWithCapacity: max]; + components = [[NSMutableArray alloc] initWithCapacity: max]; + for (count = 0; count < max; count++) + { + currentChild = [children objectAtIndex: count]; + if ([currentChild isKindOfClass: [CardGroup class]]) + [components addObject: [currentChild xmlRender]]; + else + [properties addObject: [currentChild xmlRender]]; + } + + lowerTag = [tag lowercaseString]; + [rendering appendFormat: @"<%@>", lowerTag]; + if ([properties count] > 0) + [rendering appendFormat: @"%@", + [properties componentsJoinedByString: @""]]; + if ([components count] > 0) + [rendering appendFormat: @"%@", + [components componentsJoinedByString: @""]]; + [rendering appendFormat: @"", lowerTag]; + } + + return rendering; +} + +@end + +// - (NSString *) renderElement: (CardElement *) anElement +// { +// NSMutableString *rendering; +// NSDictionary *attributes; +// NSEnumerator *keys; +// NSArray *values, *renderedAttrs; +// NSString *key, *finalRendering, *tag; + +// if (![anElement isVoid]) +// { +// rendering = [NSMutableString string]; +// if ([anElement group]) +// [rendering appendFormat: @"%@.", [anElement group]]; +// tag = [anElement tag]; +// if (!(tag && [tag length])) +// { +// tag = @""; +// [self warnWithFormat: @"card element of class '%@' has an empty tag", +// NSStringFromClass([anElement class])]; +// } + +// [rendering appendString: [tag uppercaseString]]; +// attributes = [anElement attributes]; +// keys = [[attributes allKeys] objectEnumerator]; +// while ((key = [keys nextObject])) +// { +// NSString *s; +// int i, c; + +// renderedAttrs = [[attributes objectForKey: key] renderedForCards]; +// c = [renderedAttrs count]; +// if (c > 0) +// { +// [rendering appendFormat: @";%@=", [key uppercaseString]]; + +// for (i = 0; i < c; i++) +// { +// s = [renderedAttrs objectAtIndex: i]; + +// /* We MUST quote attribute values that have a ":" in them +// and that not already quoted */ +// if ([s length] > 2 && [s rangeOfString: @":"].length && +// [s characterAtIndex: 0] != '"' && ![s hasSuffix: @"\""]) +// s = [NSString stringWithFormat: @"\"%@\"", s]; + +// [rendering appendFormat: @"%@", s]; + +// if (i+1 < c) +// [rendering appendString: @","]; +// } +// } +// } + +// values = [anElement values]; +// if ([values count] > 0) +// [rendering appendFormat: @":%@", +// [[values renderedForCards] componentsJoinedByString: @";"]]; + +// if ([rendering length] > 0) +// [rendering appendString: @"\r\n"]; + +// finalRendering = [rendering foldedForVersitCards]; +// } +// else +// finalRendering = @""; + +// return finalRendering; +// } + +// - (NSString *) renderGroup: (CardGroup *) aGroup +// { +// NSEnumerator *children; +// CardElement *currentChild; +// NSMutableString *rendering; +// NSString *groupTag; + +// rendering = [NSMutableString string]; + +// groupTag = [aGroup tag]; +// if (!(groupTag && [groupTag length])) +// { +// groupTag = @""; +// [self warnWithFormat: @"card group of class '%@' has an empty tag", +// NSStringFromClass([aGroup class])]; +// } + +// groupTag = [groupTag uppercaseString]; +// [rendering appendFormat: @"BEGIN:%@\r\n", groupTag]; +// children = [[aGroup children] objectEnumerator]; +// currentChild = [children nextObject]; +// while (currentChild) +// { +// [rendering appendString: [self render: currentChild]]; +// currentChild = [children nextObject]; +// } +// [rendering appendFormat: @"END:%@\r\n", groupTag]; + +// return rendering; +// } + +// @end diff --git a/SoObjects/Appointments/GNUmakefile b/SoObjects/Appointments/GNUmakefile index 69e6c5e62..6e1ba960e 100644 --- a/SoObjects/Appointments/GNUmakefile +++ b/SoObjects/Appointments/GNUmakefile @@ -14,7 +14,7 @@ Appointments_OBJC_FILES = \ iCalRepeatableEntityObject+SOGo.m \ iCalEvent+SOGo.m \ iCalEventChanges+SOGo.m \ - iCalPerson+SOGo.m \ + iCalPerson+SOGo.m \ iCalToDo+SOGo.m \ \ SOGoCalendarComponent.m \ @@ -22,10 +22,13 @@ Appointments_OBJC_FILES = \ SOGoTaskObject.m \ SOGoComponentOccurence.m \ SOGoAppointmentOccurence.m \ - SOGoTaskOccurence.m \ + SOGoTaskOccurence.m \ SOGoAppointmentFolder.m \ - SOGoAppointmentInboxFolder.m \ - SOGoWebAppointmentFolder.m \ + SOGoAppointmentFolderICS.m \ + SOGoAppointmentFolderObject.m \ + SOGoAppointmentFolderXML.m \ + SOGoAppointmentInboxFolder.m \ + SOGoWebAppointmentFolder.m \ SOGoAppointmentFolders.m \ SOGoFreeBusyObject.m \ SOGoUser+Appointments.m \ diff --git a/SoObjects/Appointments/SOGoAppointmentFolderICS.h b/SoObjects/Appointments/SOGoAppointmentFolderICS.h new file mode 100644 index 000000000..1b81c814b --- /dev/null +++ b/SoObjects/Appointments/SOGoAppointmentFolderICS.h @@ -0,0 +1,32 @@ +/* SOGoAppointmentFolderICS.h - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#ifndef SOGOAPPOINTMENTFOLDERICS_H +#define SOGOAPPOINTMENTFOLDERICS_H + +#import "SOGoAppointmentFolderObject.h" + +@interface SOGoAppointmentFolderICS : SOGoAppointmentFolderObject + +@end + +#endif /* SOGOAPPOINTMENTFOLDERICS_H */ diff --git a/SoObjects/Appointments/SOGoAppointmentFolderICS.m b/SoObjects/Appointments/SOGoAppointmentFolderICS.m new file mode 100644 index 000000000..5289327ee --- /dev/null +++ b/SoObjects/Appointments/SOGoAppointmentFolderICS.m @@ -0,0 +1,41 @@ + /* SOGoAppointmentFolderICS.m - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#import + +#import + +#import "SOGoAppointmentFolderICS.h" + +@implementation SOGoAppointmentFolderICS + +- (NSString *) contentAsString +{ + return [[self contentCalendar] versitString]; +} + +- (NSString *) davContentType +{ + return @"text/calendar"; +} + +@end diff --git a/SoObjects/Appointments/SOGoAppointmentFolderObject.h b/SoObjects/Appointments/SOGoAppointmentFolderObject.h new file mode 100644 index 000000000..c69d6a444 --- /dev/null +++ b/SoObjects/Appointments/SOGoAppointmentFolderObject.h @@ -0,0 +1,39 @@ +/* SOGoAppointmentFolderObject.h - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#ifndef SOGOAPPOINTMENTFOLDEROBJECT_H +#define SOGOAPPOINTMENTFOLDEROBJECT_H + +#import + +@class SOGoAppointmentFolder; + +@interface SOGoAppointmentFolderObject : SOGoObject +{ + SOGoAppointmentFolder *folder; +} + +- (iCalCalendar *) contentCalendar; + +@end + +#endif /* SOGOAPPOINTMENTFOLDEROBJECT_H */ diff --git a/SoObjects/Appointments/SOGoAppointmentFolderObject.m b/SoObjects/Appointments/SOGoAppointmentFolderObject.m new file mode 100644 index 000000000..223115ccf --- /dev/null +++ b/SoObjects/Appointments/SOGoAppointmentFolderObject.m @@ -0,0 +1,185 @@ + /* SOGoAppointmentFolderObject.m - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#import +#import +#import + +#import +#import + +#import +#import + +#import "SOGoAppointmentFolder.h" +#import "SOGoCalendarComponent.h" + +#import "SOGoAppointmentFolderObject.h" + +@implementation SOGoAppointmentFolderObject + +- (id) init +{ + if ((self = [super init])) + { + folder = nil; + } + + return self; +} + +- (void) dealloc +{ + [folder release]; + [super dealloc]; +} + +- (BOOL) isFolderish +{ + return NO; +} + +- (SOGoAppointmentFolder *) _folder +{ + NSString *folderName; + int length; + + if (!folder) + { + length = [nameInContainer length]; + if (length > 3) + { + folderName = [nameInContainer substringToIndex: length - 4]; + folder = [container lookupName: folderName + inContext: context + acquire: NO]; + [folder retain]; + } + } + + return folder; +} + +- (NSArray *) aclsForUser: (NSString *) login +{ + return [[self _folder] aclsForUser: login]; +} + +- (void) _extractTimeZones: (NSArray *) timeZones + intoDictionary: (NSMutableDictionary *) tzDict +{ + int count, max; + iCalTimeZone *timeZone; + NSString *tzId; + + max = [timeZones count]; + for (count = 0; count < max; count++) + { + timeZone = [timeZones objectAtIndex: count]; + tzId = [timeZone tzId]; + if (![tzDict objectForKey: tzId]) + [tzDict setObject: timeZone forKey: tzId]; + } +} + +- (void) _extractCalendarsData: (NSArray *) calendars + intoTimeZones: (NSMutableDictionary *) timeZones + andComponents: (NSMutableArray *) components +{ + int count, max; + iCalCalendar *calendar; + + max = [calendars count]; + for (count = 0; count < max; count++) + { + calendar = [calendars objectAtIndex: count]; + [self _extractTimeZones: [calendar timezones] + intoDictionary: timeZones]; + [components addObjectsFromArray: [calendar allObjects]]; + } +} + +- (NSArray *) _folderCalendars +{ + NSArray *names; + int count, max; + SOGoCalendarComponent *component; + NSMutableArray *calendars; + + names = [[self _folder] toOneRelationshipKeys]; + max = [names count]; + calendars = [NSMutableArray arrayWithCapacity: max]; + + for (count = 0; count < max; count++) + { + component = [folder lookupName: [names objectAtIndex: count] + inContext: context + acquire: NO]; + [calendars addObject: [component calendar: NO secure: YES]]; + } + + return calendars; +} + +- (iCalCalendar *) contentCalendar +{ + NSArray *calendars; + iCalCalendar *calendar; + NSMutableDictionary *timeZones; + NSMutableArray *components; + + calendars = [self _folderCalendars]; + timeZones = [NSMutableDictionary dictionaryWithCapacity: 16]; + components = [NSMutableArray arrayWithCapacity: [calendars count] * 2]; + [self _extractCalendarsData: calendars + intoTimeZones: timeZones andComponents: components]; + + calendar = [iCalCalendar groupWithTag: @"vcalendar"]; + [calendar setMethod: @"PUBLISH"]; + [calendar setVersion: @"2.0"]; + [calendar setProdID: @"-//Inverse inc./SOGo 1.0//EN"]; + [calendar addChildren: [timeZones allValues]]; + [calendar addChildren: components]; + + return calendar; +} + +- (id) davEntityTag +{ + return [[self _folder] davCollectionTag]; +} + +- (NSString *) contentAsString +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (NSString *) davContentType +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +@end diff --git a/SoObjects/Appointments/SOGoAppointmentFolderXML.h b/SoObjects/Appointments/SOGoAppointmentFolderXML.h new file mode 100644 index 000000000..5ebe1838c --- /dev/null +++ b/SoObjects/Appointments/SOGoAppointmentFolderXML.h @@ -0,0 +1,32 @@ +/* SOGoAppointmentFolderXML.h - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#ifndef SOGOAPPOINTMENTFOLDERXML_H +#define SOGOAPPOINTMENTFOLDERXML_H + +#import "SOGoAppointmentFolderObject.h" + +@interface SOGoAppointmentFolderXML : SOGoAppointmentFolderObject + +@end + +#endif /* SOGOAPPOINTMENTFOLDERXML_H */ diff --git a/SoObjects/Appointments/SOGoAppointmentFolderXML.m b/SoObjects/Appointments/SOGoAppointmentFolderXML.m new file mode 100644 index 000000000..bfe40bc67 --- /dev/null +++ b/SoObjects/Appointments/SOGoAppointmentFolderXML.m @@ -0,0 +1,45 @@ +/* SOGoAppointmentFolderXML.m - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * 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. + */ + +#import + +#import + +#import "SOGoAppointmentFolderXML.h" + +@implementation SOGoAppointmentFolderXML + +- (NSString *) contentAsString +{ + iCalXMLRenderer *renderer; + + renderer = [iCalXMLRenderer sharedXMLRenderer]; + + return [renderer render: [self contentCalendar]]; +} + +- (NSString *) davContentType +{ + return @"application/xml+calendar"; +} + +@end diff --git a/SoObjects/Appointments/SOGoAppointmentFolders.h b/SoObjects/Appointments/SOGoAppointmentFolders.h index 4699966af..0d392a923 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolders.h +++ b/SoObjects/Appointments/SOGoAppointmentFolders.h @@ -28,6 +28,9 @@ @class NSArray; @interface SOGoAppointmentFolders : SOGoParentFolder +{ + NSMutableArray *folderObjectKeys; +} - (NSArray *) webCalendarIds; - (void) reloadWebCalendars: (BOOL) forceReload; diff --git a/SoObjects/Appointments/SOGoAppointmentFolders.m b/SoObjects/Appointments/SOGoAppointmentFolders.m index 4931c66f8..cd14805f4 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolders.m +++ b/SoObjects/Appointments/SOGoAppointmentFolders.m @@ -47,6 +47,8 @@ #import #import "SOGoAppointmentFolder.h" +#import "SOGoAppointmentFolderICS.h" +#import "SOGoAppointmentFolderXML.h" #import "SOGoAppointmentInboxFolder.h" #import "SOGoWebAppointmentFolder.h" #import "SOGoUser+Appointments.h" @@ -63,6 +65,22 @@ @implementation SOGoAppointmentFolders +- (id) init +{ + if ((self = [super init])) + { + folderObjectKeys = nil; + } + + return self; +} + +- (void) dealloc +{ + [folderObjectKeys release]; + [super dealloc]; +} + + (NSString *) gcsFolderType { return @"Appointment"; @@ -118,6 +136,42 @@ return keys; } +- (NSArray *) folderObjectKeys +{ + NSArray *folders; + SOGoAppointmentFolder *folder; + NSString *folderObjectKey; + int count, max; + + if (!folderObjectKeys) + { + folders = [self subFolders]; + max = [folders count]; + folderObjectKeys = [[NSMutableArray alloc] initWithCapacity: max]; + for (count = 0; count < max; count++) + { + folder = [folders objectAtIndex: count]; + if ([folder isMemberOfClass: [SOGoAppointmentFolder class]] + && ![folder isSubscription]) + { + folderObjectKey = [NSString stringWithFormat: @"%@.ics", + [folder nameInContainer]]; + [folderObjectKeys addObject: folderObjectKey]; + folderObjectKey = [NSString stringWithFormat: @"%@.xml", + [folder nameInContainer]]; + [folderObjectKeys addObject: folderObjectKey]; + } + } + } + + return folderObjectKeys; +} + +- (NSArray *) toOneRelationshipKeys +{ + return [self folderObjectKeys]; +} + - (id) lookupName: (NSString *) name inContext: (WOContext *) lookupContext acquire: (BOOL) acquire @@ -127,6 +181,17 @@ if ([name isEqualToString: @"inbox"]) obj = [SOGoAppointmentInboxFolder objectWithName: name inContainer: self]; + else if ([[self folderObjectKeys] containsObject: name]) + { + if ([name hasSuffix: @".ics"]) + obj = [SOGoAppointmentFolderICS objectWithName: name + inContainer: self]; + else if ([name hasSuffix: @".xml"]) + obj = [SOGoAppointmentFolderXML objectWithName: name + inContainer: self]; + else + obj = nil; + } else obj = [super lookupName: name inContext: lookupContext acquire: NO]; diff --git a/SoObjects/Appointments/product.plist b/SoObjects/Appointments/product.plist index 865942b97..ac04c7d41 100644 --- a/SoObjects/Appointments/product.plist +++ b/SoObjects/Appointments/product.plist @@ -22,12 +22,12 @@ "ViewDAndTOfPublicRecords" = ( "Owner", "PublicDAndTViewer" ); "ViewDAndTOfPrivateRecords" = ( "Owner", "PrivateDAndTViewer" ); "ViewDAndTOfConfidentialRecords" = ( "Owner", "ConfidentialDAndTViewer" ); - "ModifyPublicRecords" = ( ); - "ModifyPrivateRecords" = ( ); - "ModifyConfidentialRecords" = ( ); - "RespondToPublicRecords" = ( ); - "RespondToPrivateRecords" = ( ); - "RespondToConfidentialRecords" = ( ); + "ModifyPublicRecords" = ( "NoOne" ); + "ModifyPrivateRecords" = ( "NoOne" ); + "ModifyConfidentialRecords" = ( "NoOne" ); + "RespondToPublicRecords" = ( "NoOne" ); + "RespondToPrivateRecords" = ( "NoOne" ); + "RespondToConfidentialRecords" = ( "NoOne" ); }; }; SOGoAppointmentFolder = { @@ -49,10 +49,25 @@ "RespondToConfidentialRecords" = ( "Owner", "ConfidentialModifier", "ConfidentialResponder" ); }; }; + SOGoAppointmentFolderObject = { + superclass = "SOGoAppointmentFolder"; + protectedBy = "Access Contents Information"; + defaultRoles = { + "Access Contents Information" = ( "Owner", "PublicResponder", "PublicModifier", "PublicViewer", "PublicDAndTViewer", "PrivateResponder", "PrivateModifier", "PrivateViewer", "PrivateDAndTViewer", "ConfidentialResponder", "ConfidentialModifier", "ConfidentialViewer", "ConfidentialDAndTViewer", "AuthorizedSubscriber" ); + "WebDAV Access" = ( "Owner", "Authenticated", "PublicUser" ); + "Change Images And Files" = ( "NoOne" ); + }; + }; + SOGoAppointmentFolderICS = { + superclass = "SOGoAppointmentFolderObject"; + }; + SOGoAppointmentFolderXML = { + superclass = "SOGoAppointmentFolderObject"; + }; SOGoAppointmentInboxFolder = { superclass = "SOGoAppointmentFolder"; defaultRoles = { - "Access Contents Information" = ( "Owner", "AuthorizedSubscriber" ); + "Access Contents Information" = ( "Owner" ); }; }; SOGoCalendarComponent = { diff --git a/SoObjects/SOGo/SOGoFolder.h b/SoObjects/SOGo/SOGoFolder.h index 24de0805b..cc97cf153 100644 --- a/SoObjects/SOGo/SOGoFolder.h +++ b/SoObjects/SOGo/SOGoFolder.h @@ -41,6 +41,9 @@ - (NSString *) folderType; +- (NSArray *) toOneRelationshipKeys; +- (NSArray *) toManyRelationshipKeys; + - (BOOL) isValidContentName: (NSString *) name; /* sorting */ diff --git a/SoObjects/SOGo/SOGoGCSFolder.h b/SoObjects/SOGo/SOGoGCSFolder.h index 76ee7185c..6c8022786 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.h +++ b/SoObjects/SOGo/SOGoGCSFolder.h @@ -116,6 +116,8 @@ - (NSDictionary *) davSQLFieldsTable; - (NSDictionary *) parseDAVRequestedProperties: (DOMElement *) propElement; +- (NSString *) davCollectionTag; + @end #endif /* __SOGo_SOGoGCSFolder_H__ */