2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "iCalEvent.h"
23 #include "iCalPerson.h"
24 #include "iCalEventChanges.h"
25 #include "iCalRecurrenceRule.h"
26 #include "iCalRenderer.h"
27 #include <NGExtensions/NGCalendarDateRange.h>
30 @interface NSString(DurationTimeInterval)
31 - (NSTimeInterval)durationAsTimeInterval;
34 @implementation iCalEvent
37 return [super version] + 0 /* v0 */;
40 NSAssert2([super version] == 0,
41 @"invalid superclass (%@) version %i !",
42 NSStringFromClass([self superclass]), [super version]);
46 [self->endDate release];
47 [self->duration release];
48 [self->transparency release];
54 - (id)copyWithZone:(NSZone *)_zone {
57 new = [super copyWithZone:_zone];
59 new->endDate = [self->endDate copyWithZone:_zone];
60 new->duration = [self->duration copyWithZone:_zone];
61 new->transparency = [self->transparency copyWithZone:_zone];
68 - (void)setEndDate:(NSCalendarDate *)_date {
70 if (self->endDate == _date) return;
72 self->endDate = [_date retain];
75 - (NSCalendarDate *)endDate {
76 if ([self hasEndDate])
79 if ([self hasDuration] && (self->startDate != nil)) {
80 return [[self startDate] dateByAddingYears:0 months:0 days:0
82 seconds:[self durationAsTimeInterval]];
87 return self->endDate ? YES : NO;
90 - (void)setDuration:(NSString *)_value {
91 ASSIGNCOPY(self->duration, _value);
93 - (NSString *)duration {
94 // eg: "DURATION:PT1H"
95 if ([self hasDuration])
96 return self->duration;
101 - (BOOL)hasDuration {
102 return self->duration ? YES : NO;
104 - (NSTimeInterval)durationAsTimeInterval {
108 P2H30M - "2 hours 30 minutes"
110 dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
112 dur-date = dur-day [dur-time]
113 dur-time = "T" (dur-hour / dur-minute / dur-second)
114 dur-week = 1*DIGIT "W"
115 dur-hour = 1*DIGIT "H" [dur-minute]
116 dur-minute = 1*DIGIT "M" [dur-second]
117 dur-second = 1*DIGIT "S"
118 dur-day = 1*DIGIT "D"
122 return [self->duration durationAsTimeInterval];
124 if (self->endDate != nil && self->startDate != nil)
125 /* calculate duration using enddate */
126 return [[self endDate] timeIntervalSinceDate:[self startDate]];
131 - (void)setTransparency:(NSString *)_transparency {
132 ASSIGNCOPY(self->transparency, _transparency);
134 - (NSString *)transparency {
135 return self->transparency;
143 s = [self transparency];
144 if (s && [[s uppercaseString] isEqualToString:@"TRANSPARENT"])
146 return YES; /* default is OPAQUE, see RFC2445, Section 4.8.2.7 */
150 The problem is, that startDate/endDate are inappropriately modelled here.
151 We'd need to have a special iCalDate in order to fix all the mess.
152 For the time being, we chose allday to mean 00:00 - 23:59 in startDate's
158 if (![self hasEndDate])
161 ed = [[[self endDate] copy] autorelease];
162 [ed setTimeZone:[self->startDate timeZone]];
163 if (([self->startDate hourOfDay] == 0) &&
164 ([self->startDate minuteOfHour] == 0) &&
165 ([ed hourOfDay] == 23) &&
166 ([ed minuteOfHour] == 59))
171 - (BOOL)isWithinCalendarDateRange:(NGCalendarDateRange *)_range {
172 if (![self isRecurrent]) {
173 if (self->startDate && self->endDate) {
174 NGCalendarDateRange *r;
176 r = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
177 endDate:self->endDate];
178 return [_range containsDateRange:r];
181 return [_range containsDate:self->startDate];
185 NGCalendarDateRange *fir;
187 fir = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
188 endDate:self->endDate];
190 return [self isWithinCalendarDateRange:_range
191 firstInstanceCalendarDateRange:fir];
196 - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
197 NGCalendarDateRange *fir;
199 if (![self isRecurrent])
202 fir = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
203 endDate:self->endDate];
204 return [self recurrenceRangesWithinCalendarDateRange:_r
205 firstInstanceCalendarDateRange:fir];
208 - (NSCalendarDate *)lastPossibleRecurrenceStartDate {
209 NGCalendarDateRange *fir;
211 if (![self isRecurrent])
214 fir = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
215 endDate:self->endDate];
216 return [self lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange:fir];
221 - (NSString *)entityName {
227 - (NSString *)description {
230 ms = [NSMutableString stringWithCapacity:128];
231 [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
233 if (self->uid) [ms appendFormat:@" uid=%@", self->uid];
234 if (self->startDate) [ms appendFormat:@" from=%@", self->startDate];
235 if (self->endDate) [ms appendFormat:@" to=%@", self->endDate];
236 if (self->summary) [ms appendFormat:@" summary=%@", self->summary];
239 [ms appendFormat:@" organizer=%@", self->organizer];
241 [ms appendFormat:@" attendees=%@", self->attendees];
243 if ([self hasAlarms])
244 [ms appendFormat:@" alarms=%@", self->alarms];
246 [ms appendString:@">"];
252 - (iCalEventChanges *)getChangesRelativeToEvent:(iCalEvent *)_event {
253 return [iCalEventChanges changesFromEvent:_event
257 /* generating iCal content */
259 - (NSString *)vEventString {
260 return [[iCalRenderer sharedICalendarRenderer] vEventStringForEvent:self];
265 @implementation NSString(DurationTimeInterval)
267 - (NSTimeInterval)durationAsTimeInterval {
271 P2H30M - "2 hours 30 minutes"
273 dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
275 dur-date = dur-day [dur-time]
276 dur-time = "T" (dur-hour / dur-minute / dur-second)
277 dur-week = 1*DIGIT "W"
278 dur-hour = 1*DIGIT "H" [dur-minute]
279 dur-minute = 1*DIGIT "M" [dur-second]
280 dur-second = 1*DIGIT "S"
281 dur-day = 1*DIGIT "D"
288 if (![self hasPrefix:@"P"]) {
289 NSLog(@"Cannot parse iCal duration value: '%@'", self);
295 for (i = 1, len = [self length], isTime = NO; i < len; i++) {
298 c = [self characterAtIndex:i];
299 if (c == 't' || c == 'T') {
306 val = (val * 10) + (c - 48);
312 ti += (val * 7 * 24 * 60 * 60);
315 ti += (val * 24 * 60 * 60);
318 ti += (val * 60 * 60);
327 [self logWithFormat:@"cannot process duration unit: '%c'", c];
335 @end /* NSString(DurationTimeInterval) */