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 "iCalDateHolder.h"
24 #include "NSCalendarDate+ICal.h"
31 interval = rrInterval;
32 bysecond = rrBySecondList;
33 byminute = rrByMinuteList;
34 byhour = rrByHourList;
36 bymonthday = rrByMonthDayList;
37 byyearday = rrByYearDayList;
38 byweekno = rrByWeekNumberList;
39 bymonth = rrByMonthList;
40 bysetpos = rrBySetPosList;
44 @interface iCalDateHolder (PrivateAPI)
45 - (void)setString:(NSString *)_value;
46 - (id)awakeAfterUsingSaxDecoder:(id)_decoder;
49 @interface iCalRecurrenceRule (PrivateAPI)
50 - (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day;
51 - (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay;
54 - (NSString *)byDayList;
57 - (void)setRrule:(NSString *)_rrule;
60 @implementation iCalRecurrenceRule
63 static BOOL didInit = NO;
69 + (id)recurrenceRuleWithICalRepresentation:(NSString *)_iCalRep {
70 iCalRecurrenceRule *r;
72 r = [[[self alloc] init] autorelease];
73 [r setRrule:_iCalRep];
80 self->byDay.weekStart = iCalWeekDayMonday;
87 [self->untilDate release];
88 [self->rrule release];
95 - (void)setFrequency:(iCalRecurrenceFrequency)_frequency {
96 self->frequency = _frequency;
98 - (iCalRecurrenceFrequency)frequency {
99 return self->frequency;
102 - (void)setRepeatCount:(unsigned)_repeatCount {
103 self->repeatCount = _repeatCount;
105 - (unsigned)repeatCount {
106 return self->repeatCount;
109 - (void)setUntilDate:(NSCalendarDate *)_untilDate {
110 ASSIGN(self->untilDate, _untilDate);
112 - (NSCalendarDate *)untilDate {
113 return self->untilDate;
116 - (void)setRepeatInterval:(int)_repeatInterval {
117 self->interval = _repeatInterval;
119 - (int)repeatInterval {
120 return self->interval;
123 - (void)setWeekStart:(iCalWeekDay)_weekStart {
124 self->byDay.weekStart = _weekStart;
126 - (iCalWeekDay)weekStart {
127 return self->byDay.weekStart;
131 return (self->repeatCount != 0 || self->untilDate) ? NO : YES;
137 - (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day {
138 _day = [_day uppercaseString];
139 if ([_day isEqualToString:@"MO"])
140 return iCalWeekDayMonday;
141 else if ([_day isEqualToString:@"TU"])
142 return iCalWeekDayTuesday;
143 else if ([_day isEqualToString:@"WE"])
144 return iCalWeekDayWednesday;
145 else if ([_day isEqualToString:@"TH"])
146 return iCalWeekDayThursday;
147 else if ([_day isEqualToString:@"FR"])
148 return iCalWeekDayFriday;
149 else if ([_day isEqualToString:@"SA"])
150 return iCalWeekDaySaturday;
151 else if ([_day isEqualToString:@"SU"])
152 return iCalWeekDaySunday;
154 [NSException raise:NSGenericException
155 format:@"Incorrect weekDay '%@' specified!", _day];
156 return iCalWeekDayMonday; /* keep compiler happy */
159 - (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay {
160 switch (self->byDay.weekStart) {
161 case iCalWeekDayMonday:
163 case iCalWeekDayTuesday:
165 case iCalWeekDayWednesday:
167 case iCalWeekDayThursday:
169 case iCalWeekDayFriday:
171 case iCalWeekDaySaturday:
173 case iCalWeekDaySunday:
181 switch (self->frequency) {
182 case iCalRecurrenceFrequenceWeekly:
184 case iCalRecurrenceFrequenceMonthly:
186 case iCalRecurrenceFrequenceDaily:
188 case iCalRecurrenceFrequenceYearly:
190 case iCalRecurrenceFrequenceHourly:
192 case iCalRecurrenceFrequenceMinutely:
194 case iCalRecurrenceFrequenceSecondly:
197 return @"UNDEFINED?";
202 return [self iCalRepresentationForWeekDay:self->byDay.weekStart];
207 Each BYDAY value can also be preceded by a positive (+n) or negative
208 (-n) integer. If present, this indicates the nth occurrence of the
209 specific day within the MONTHLY or YEARLY RRULE. For example, within
210 a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday
211 within the month, whereas -1MO represents the last Monday of the
212 month. If an integer modifier is not present, it means all days of
213 this type within the specified frequency. For example, within a
214 MONTHLY rule, MO represents all Mondays within the month.
216 - (NSString *)byDayList {
221 s = [NSMutableString stringWithCapacity:20];
223 day = iCalWeekDayMonday;
225 for (i = 0; i < 7; i++) {
226 if (self->byDay.mask && day) {
228 [s appendString:@","];
229 [s appendString:[self iCalRepresentationForWeekDay:day]];
239 - (void)setRrule:(NSString *)_rrule {
240 ASSIGN(self->rrule, _rrule);
244 /* Processing existing rrule */
246 - (void)_processRule {
250 props = [self->rrule componentsSeparatedByString:@";"];
251 count = [props count];
252 for (i = 0; i < count; i++) {
253 NSString *prop, *key, *value;
256 prop = [props objectAtIndex:i];
257 r = [prop rangeOfString:@"="];
259 key = [prop substringToIndex:r.location];
260 value = [prop substringFromIndex:NSMaxRange(r)];
266 [self takeValue:value forKey:[key lowercaseString]];
273 - (void)setFreq:(NSString *)_freq {
274 _freq = [_freq uppercaseString];
275 if ([_freq isEqualToString:@"WEEKLY"])
276 self->frequency = iCalRecurrenceFrequenceWeekly;
277 else if ([_freq isEqualToString:@"MONTHLY"])
278 self->frequency = iCalRecurrenceFrequenceMonthly;
279 else if ([_freq isEqualToString:@"DAILY"])
280 self->frequency = iCalRecurrenceFrequenceDaily;
281 else if ([_freq isEqualToString:@"YEARLY"])
282 self->frequency = iCalRecurrenceFrequenceYearly;
283 else if ([_freq isEqualToString:@"HOURLY"])
284 self->frequency = iCalRecurrenceFrequenceHourly;
285 else if ([_freq isEqualToString:@"MINUTELY"])
286 self->frequency = iCalRecurrenceFrequenceMinutely;
287 else if ([_freq isEqualToString:@"SECONDLY"])
288 self->frequency = iCalRecurrenceFrequenceSecondly;
290 [NSException raise:NSGenericException
291 format:@"Incorrect frequency '%@' specified!", _freq];
294 - (void)setInterval:(NSString *)_interval {
295 self->interval = [_interval intValue];
297 - (void)setCount:(NSString *)_count {
298 self->repeatCount = [_count unsignedIntValue];
300 - (void)setUntil:(NSString *)_until {
302 NSCalendarDate *date;
304 dh = [[iCalDateHolder alloc] init];
305 [dh setString:_until];
306 date = [dh awakeAfterUsingSaxDecoder:nil];
307 ASSIGN(self->untilDate, date);
311 - (void)setWkst:(NSString *)_weekStart {
312 self->byDay.weekStart = [self weekDayFromICalRepresentation:_weekStart];
315 - (void)setByday:(NSString *)_byDayList {
319 self->byDay.mask = 0;
320 days = [_byDayList componentsSeparatedByString:@","];
321 count = [days count];
322 for (i = 0; i < count; i++) {
326 iCalDay = [days objectAtIndex:i];
327 day = [self weekDayFromICalRepresentation:iCalDay];
328 self->byDay.mask |= day;
332 /* key/value coding */
334 - (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
335 [self warnWithFormat:@"Don't know how to process '%@'!", _key];
341 - (NSString *)iCalRepresentation {
344 s = [NSMutableString stringWithCapacity:80];
345 [s appendString:@"FREQ="];
346 [s appendString:[self freq]];
347 if ([self repeatInterval] != 1) {
348 [s appendFormat:@";INTERVAL=%d", [self repeatInterval]];
350 if (![self isInfinite]) {
351 if ([self repeatCount] > 0) {
352 [s appendFormat:@";COUNT=%d", [self repeatCount]];
355 [s appendString:@";UNTIL="];
356 [s appendString:[[self untilDate] icalString]];
359 if (self->byDay.weekStart != iCalWeekDayMonday) {
360 [s appendString:@";WKST="];
361 [s appendString:[self iCalRepresentationForWeekDay:self->byDay.weekStart]];
363 if (self->byDay.mask != 0) {
364 [s appendString:@";BYDAY="];
365 [s appendString:[self byDayList]];