]> err.no Git - sope/blob - sope-ical/NGiCal/iCalEvent.m
bumped Xcode dyld versions
[sope] / sope-ical / NGiCal / iCalEvent.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
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>
28 #include "common.h"
29
30 @interface NSString(DurationTimeInterval)
31 - (NSTimeInterval)durationAsTimeInterval;
32 @end
33
34 @implementation iCalEvent
35
36 - (void)dealloc {
37   [self->endDate      release];
38   [self->duration     release];
39   [self->transparency release];
40   [super dealloc];
41 }
42
43 /* accessors */
44
45 - (void)setEndDate:(NSCalendarDate *)_date {
46   id tmp;
47   if (self->endDate == _date) return;
48   tmp = self->endDate;
49   self->endDate = [_date retain];
50   [tmp release];
51 }
52 - (NSCalendarDate *)endDate {
53   if ([self hasEndDate])
54     return self->endDate;
55   
56   if ([self hasDuration] && (self->startDate != nil)) {
57     return [[self startDate] dateByAddingYears:0 months:0 days:0
58                              hours:0 minutes:0 
59                              seconds:[self durationAsTimeInterval]];
60   }
61   return nil;
62 }
63 - (BOOL)hasEndDate {
64   return self->endDate ? YES : NO;
65 }
66
67 - (void)setDuration:(NSString *)_value {
68   ASSIGNCOPY(self->duration, _value);
69 }
70 - (NSString *)duration {
71   // eg: "DURATION:PT1H"
72   if ([self hasDuration])
73     return self->duration;
74   
75   // TODO: calculate
76   return nil;
77 }
78 - (BOOL)hasDuration {
79   return self->duration ? YES : NO;
80 }
81 - (NSTimeInterval)durationAsTimeInterval {
82   /*
83     eg: DURATION:PT1H
84     P      - "period"
85     P2H30M - "2 hours 30 minutes"
86
87      dur-value  = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
88
89      dur-date   = dur-day [dur-time]
90      dur-time   = "T" (dur-hour / dur-minute / dur-second)
91      dur-week   = 1*DIGIT "W"
92      dur-hour   = 1*DIGIT "H" [dur-minute]
93      dur-minute = 1*DIGIT "M" [dur-second]
94      dur-second = 1*DIGIT "S"
95      dur-day    = 1*DIGIT "D"
96   */
97   
98   if (self->duration)
99     return [self->duration durationAsTimeInterval];
100   
101   if (self->endDate != nil && self->startDate != nil)
102     /* calculate duration using enddate */
103     return [[self endDate] timeIntervalSinceDate:[self startDate]];
104   
105   return 0.0;
106 }
107
108 - (void)setTransparency:(NSString *)_transparency {
109   ASSIGNCOPY(self->transparency, _transparency);
110 }
111 - (NSString *)transparency {
112   return self->transparency;
113 }
114
115 /* convenience */
116
117 - (BOOL)isOpaque {
118   NSString *s;
119   
120   s = [self transparency];
121   if (s && [[s uppercaseString] isEqualToString:@"TRANSPARENT"])
122     return NO;
123   return YES; /* default is OPAQUE, see RFC2445, Section 4.8.2.7 */
124 }
125
126 /* TODO: FIX THIS!
127    The problem is, that startDate/endDate are inappropriately modelled here.
128    We'd need to have a special iCalDate in order to fix all the mess.
129    For the time being, we chose allday to mean 00:00 - 23:59 in startDate's
130    timezone.
131 */
132 - (BOOL)isAllDay {
133   NSCalendarDate *ed;
134
135   if (![self hasEndDate])
136     return NO;
137   
138   ed = [[[self endDate] copy] autorelease];
139   [ed setTimeZone:[self->startDate timeZone]];
140   if (([self->startDate hourOfDay]    ==  0) &&
141       ([self->startDate minuteOfHour] ==  0) &&
142       ([ed hourOfDay]                 == 23) &&
143       ([ed minuteOfHour]              == 59))
144       return YES;
145   return NO;
146 }
147
148 - (BOOL)isWithinCalendarDateRange:(NGCalendarDateRange *)_range {
149   if (![self isRecurrent]) {
150     if (self->startDate && self->endDate) {
151       NGCalendarDateRange *r;
152       
153       r = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
154                                endDate:self->endDate];
155       return [_range containsDateRange:r];
156     }
157     else {
158       return [_range containsDate:self->startDate];
159     }
160   }
161   else {
162     NGCalendarDateRange *fir;
163
164     fir = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
165                                endDate:self->endDate];
166     
167     return [self isWithinCalendarDateRange:_range
168                  firstInstanceCalendarDateRange:fir];
169   }
170   return NO;
171 }
172
173 - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
174   NGCalendarDateRange *fir;
175   
176   if (![self isRecurrent])
177     return nil;
178   
179   fir = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
180                              endDate:self->endDate];
181   return [self recurrenceRangesWithinCalendarDateRange:_r
182                firstInstanceCalendarDateRange:fir];
183 }
184
185 - (NSCalendarDate *)lastPossibleRecurrenceStartDate {
186   NGCalendarDateRange *fir;
187
188   if (![self isRecurrent])
189     return nil;
190
191   fir = [NGCalendarDateRange calendarDateRangeWithStartDate:self->startDate
192                              endDate:self->endDate];
193   return [self lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange:fir];
194 }
195
196 /* ical typing */
197
198 - (NSString *)entityName {
199   return @"vevent";
200 }
201
202 /* descriptions */
203
204 - (NSString *)description {
205   NSMutableString *ms;
206
207   ms = [NSMutableString stringWithCapacity:128];
208   [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
209
210   if (self->uid)       [ms appendFormat:@" uid=%@", self->uid];
211   if (self->startDate) [ms appendFormat:@" from=%@", self->startDate];
212   if (self->endDate)   [ms appendFormat:@" to=%@", self->endDate];
213   if (self->summary)   [ms appendFormat:@" summary=%@", self->summary];
214   
215   if (self->organizer)
216     [ms appendFormat:@" organizer=%@", self->organizer];
217   if (self->attendees)
218     [ms appendFormat:@" attendees=%@", self->attendees];
219   
220   if ([self hasAlarms])
221     [ms appendFormat:@" alarms=%@", self->alarms];
222   
223   [ms appendString:@">"];
224   return ms;
225 }
226
227 /* changes */
228
229 - (iCalEventChanges *)getChangesRelativeToEvent:(iCalEvent *)_event {
230   return [iCalEventChanges changesFromEvent:_event
231                            toEvent:self];
232 }
233
234 /* generating iCal content */
235
236 - (NSString *)vEventString {
237   return [[iCalRenderer sharedICalendarRenderer] vEventStringForEvent:self];
238 }
239
240 @end /* iCalEvent */
241
242 @implementation NSString(DurationTimeInterval)
243
244 - (NSTimeInterval)durationAsTimeInterval {
245   /*
246     eg: DURATION:PT1H
247     P      - "period"
248     P2H30M - "2 hours 30 minutes"
249
250      dur-value  = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
251
252      dur-date   = dur-day [dur-time]
253      dur-time   = "T" (dur-hour / dur-minute / dur-second)
254      dur-week   = 1*DIGIT "W"
255      dur-hour   = 1*DIGIT "H" [dur-minute]
256      dur-minute = 1*DIGIT "M" [dur-second]
257      dur-second = 1*DIGIT "S"
258      dur-day    = 1*DIGIT "D"
259   */
260   unsigned       i, len;
261   NSTimeInterval ti;
262   BOOL           isTime;
263   int            val;
264     
265   if (![self hasPrefix:@"P"]) {
266     NSLog(@"Cannot parse iCal duration value: '%@'", self);
267     return 0.0;
268   }
269     
270   ti  = 0.0;
271   val = 0;
272   for (i = 1, len = [self length], isTime = NO; i < len; i++) {
273     unichar c;
274       
275     c = [self characterAtIndex:i];
276     if (c == 't' || c == 'T') {
277       isTime = YES;
278       val = 0;
279       continue;
280     }
281       
282     if (isdigit(c)) {
283       val = (val * 10) + (c - 48);
284       continue;
285     }
286       
287     switch (c) {
288     case 'W': /* week */
289       ti += (val * 7 * 24 * 60 * 60);
290       break;
291     case 'D': /* day  */
292       ti += (val * 24 * 60 * 60);
293       break;
294     case 'H': /* hour */
295       ti += (val * 60 * 60);
296       break;
297     case 'M': /* min  */
298       ti += (val * 60);
299       break;
300     case 'S': /* sec  */
301       ti += val;
302       break;
303     default:
304       [self logWithFormat:@"cannot process duration unit: '%c'", c];
305       break;
306     }
307     val = 0;
308   }
309   return ti;
310 }
311
312 @end /* NSString(DurationTimeInterval) */