2 Copyright (C) 2004-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 "iCalRecurrenceRule.h"
23 #include "NSCalendarDate+ICal.h"
30 interval = rrInterval;
31 bysecond = rrBySecondList;
32 byminute = rrByMinuteList;
33 byhour = rrByHourList;
35 bymonthday = rrByMonthDayList;
36 byyearday = rrByYearDayList;
37 byweekno = rrByWeekNumberList;
38 bymonth = rrByMonthList;
39 bysetpos = rrBySetPosList;
43 @interface iCalRecurrenceRule (PrivateAPI)
44 - (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day;
45 - (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay;
48 - (NSString *)byDayList;
51 - (void)setRrule:(NSString *)_rrule;
54 @implementation iCalRecurrenceRule
57 static BOOL didInit = NO;
63 + (id)recurrenceRuleWithICalRepresentation:(NSString *)_iCalRep {
64 iCalRecurrenceRule *r;
66 r = [[[self alloc] init] autorelease];
67 [r setRrule:_iCalRep];
74 self->byDay.weekStart = iCalWeekDayMonday;
81 [self->untilDate release];
82 [self->rrule release];
89 - (void)setFrequency:(iCalRecurrenceFrequency)_frequency {
90 self->frequency = _frequency;
92 - (iCalRecurrenceFrequency)frequency {
93 return self->frequency;
96 - (void)setRepeatCount:(unsigned)_repeatCount {
97 self->repeatCount = _repeatCount;
99 - (unsigned)repeatCount {
100 return self->repeatCount;
103 - (void)setUntilDate:(NSCalendarDate *)_untilDate {
104 ASSIGN(self->untilDate, _untilDate);
106 - (NSCalendarDate *)untilDate {
107 return self->untilDate;
110 - (void)setRepeatInterval:(int)_repeatInterval {
111 self->interval = _repeatInterval;
113 - (int)repeatInterval {
114 return self->interval;
117 - (void)setWeekStart:(iCalWeekDay)_weekStart {
118 self->byDay.weekStart = _weekStart;
120 - (iCalWeekDay)weekStart {
121 return self->byDay.weekStart;
124 - (void)setByDayMask:(unsigned)_mask {
125 self->byDay.mask = _mask;
127 - (unsigned)byDayMask {
128 return self->byDay.mask;
132 return (self->repeatCount != 0 || self->untilDate) ? NO : YES;
138 - (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day {
139 _day = [_day uppercaseString];
140 if ([_day isEqualToString:@"MO"])
141 return iCalWeekDayMonday;
142 else if ([_day isEqualToString:@"TU"])
143 return iCalWeekDayTuesday;
144 else if ([_day isEqualToString:@"WE"])
145 return iCalWeekDayWednesday;
146 else if ([_day isEqualToString:@"TH"])
147 return iCalWeekDayThursday;
148 else if ([_day isEqualToString:@"FR"])
149 return iCalWeekDayFriday;
150 else if ([_day isEqualToString:@"SA"])
151 return iCalWeekDaySaturday;
152 else if ([_day isEqualToString:@"SU"])
153 return iCalWeekDaySunday;
155 [NSException raise:NSGenericException
156 format:@"Incorrect weekDay '%@' specified!", _day];
157 return iCalWeekDayMonday; /* keep compiler happy */
160 - (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay {
162 case iCalWeekDayMonday:
164 case iCalWeekDayTuesday:
166 case iCalWeekDayWednesday:
168 case iCalWeekDayThursday:
170 case iCalWeekDayFriday:
172 case iCalWeekDaySaturday:
174 case iCalWeekDaySunday:
182 switch (self->frequency) {
183 case iCalRecurrenceFrequenceWeekly:
185 case iCalRecurrenceFrequenceMonthly:
187 case iCalRecurrenceFrequenceDaily:
189 case iCalRecurrenceFrequenceYearly:
191 case iCalRecurrenceFrequenceHourly:
193 case iCalRecurrenceFrequenceMinutely:
195 case iCalRecurrenceFrequenceSecondly:
198 return @"UNDEFINED?";
203 return [self iCalRepresentationForWeekDay:self->byDay.weekStart];
208 Each BYDAY value can also be preceded by a positive (+n) or negative
209 (-n) integer. If present, this indicates the nth occurrence of the
210 specific day within the MONTHLY or YEARLY RRULE. For example, within
211 a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday
212 within the month, whereas -1MO represents the last Monday of the
213 month. If an integer modifier is not present, it means all days of
214 this type within the specified frequency. For example, within a
215 MONTHLY rule, MO represents all Mondays within the month.
217 - (NSString *)byDayList {
219 unsigned i, mask, day;
222 s = [NSMutableString stringWithCapacity:20];
224 mask = self->byDay.mask;
225 day = iCalWeekDayMonday;
226 for (i = 0; i < 7; i++) {
229 [s appendString:@","];
230 [s appendString:[self iCalRepresentationForWeekDay:day]];
240 - (void)setRrule:(NSString *)_rrule {
241 ASSIGN(self->rrule, _rrule);
245 /* Processing existing rrule */
247 - (void)_processRule {
251 props = [self->rrule componentsSeparatedByString:@";"];
252 count = [props count];
253 for (i = 0; i < count; i++) {
254 NSString *prop, *key, *value;
257 prop = [props objectAtIndex:i];
258 r = [prop rangeOfString:@"="];
260 key = [prop substringToIndex:r.location];
261 value = [prop substringFromIndex:NSMaxRange(r)];
267 [self takeValue:value forKey:[key lowercaseString]];
274 - (void)setFreq:(NSString *)_freq {
275 _freq = [_freq uppercaseString];
276 if ([_freq isEqualToString:@"WEEKLY"])
277 self->frequency = iCalRecurrenceFrequenceWeekly;
278 else if ([_freq isEqualToString:@"MONTHLY"])
279 self->frequency = iCalRecurrenceFrequenceMonthly;
280 else if ([_freq isEqualToString:@"DAILY"])
281 self->frequency = iCalRecurrenceFrequenceDaily;
282 else if ([_freq isEqualToString:@"YEARLY"])
283 self->frequency = iCalRecurrenceFrequenceYearly;
284 else if ([_freq isEqualToString:@"HOURLY"])
285 self->frequency = iCalRecurrenceFrequenceHourly;
286 else if ([_freq isEqualToString:@"MINUTELY"])
287 self->frequency = iCalRecurrenceFrequenceMinutely;
288 else if ([_freq isEqualToString:@"SECONDLY"])
289 self->frequency = iCalRecurrenceFrequenceSecondly;
291 [NSException raise:NSGenericException
292 format:@"Incorrect frequency '%@' specified!", _freq];
295 - (void)setInterval:(NSString *)_interval {
296 self->interval = [_interval intValue];
298 - (void)setCount:(NSString *)_count {
299 self->repeatCount = [_count unsignedIntValue];
301 - (void)setUntil:(NSString *)_until {
302 NSCalendarDate *date;
304 date = [NSCalendarDate calendarDateWithICalRepresentation:_until];
305 ASSIGN(self->untilDate, date);
308 - (void)setWkst:(NSString *)_weekStart {
309 self->byDay.weekStart = [self weekDayFromICalRepresentation:_weekStart];
312 - (void)setByday:(NSString *)_byDayList {
316 self->byDay.mask = 0;
317 days = [_byDayList componentsSeparatedByString:@","];
318 count = [days count];
319 for (i = 0; i < count; i++) {
323 iCalDay = [days objectAtIndex:i];
324 day = [self weekDayFromICalRepresentation:iCalDay];
325 self->byDay.mask |= day;
329 /* key/value coding */
331 - (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
332 [self warnWithFormat:@"Don't know how to process '%@'!", _key];
338 - (NSString *)iCalRepresentation {
341 s = [NSMutableString stringWithCapacity:80];
342 [s appendString:@"FREQ="];
343 [s appendString:[self freq]];
344 if ([self repeatInterval] != 1) {
345 [s appendFormat:@";INTERVAL=%d", [self repeatInterval]];
347 if (![self isInfinite]) {
348 if ([self repeatCount] > 0) {
349 [s appendFormat:@";COUNT=%d", [self repeatCount]];
352 [s appendString:@";UNTIL="];
353 [s appendString:[[self untilDate] icalString]];
356 if (self->byDay.weekStart != iCalWeekDayMonday) {
357 [s appendString:@";WKST="];
358 [s appendString:[self iCalRepresentationForWeekDay:self->byDay.weekStart]];
360 if (self->byDay.mask != 0) {
361 [s appendString:@";BYDAY="];
362 [s appendString:[self byDayList]];