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;
130 - (void)setByDayMask:(unsigned)_mask {
131 self->byDay.mask = _mask;
133 - (unsigned)byDayMask {
134 return self->byDay.mask;
138 return (self->repeatCount != 0 || self->untilDate) ? NO : YES;
144 - (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day {
145 _day = [_day uppercaseString];
146 if ([_day isEqualToString:@"MO"])
147 return iCalWeekDayMonday;
148 else if ([_day isEqualToString:@"TU"])
149 return iCalWeekDayTuesday;
150 else if ([_day isEqualToString:@"WE"])
151 return iCalWeekDayWednesday;
152 else if ([_day isEqualToString:@"TH"])
153 return iCalWeekDayThursday;
154 else if ([_day isEqualToString:@"FR"])
155 return iCalWeekDayFriday;
156 else if ([_day isEqualToString:@"SA"])
157 return iCalWeekDaySaturday;
158 else if ([_day isEqualToString:@"SU"])
159 return iCalWeekDaySunday;
161 [NSException raise:NSGenericException
162 format:@"Incorrect weekDay '%@' specified!", _day];
163 return iCalWeekDayMonday; /* keep compiler happy */
166 - (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay {
168 case iCalWeekDayMonday:
170 case iCalWeekDayTuesday:
172 case iCalWeekDayWednesday:
174 case iCalWeekDayThursday:
176 case iCalWeekDayFriday:
178 case iCalWeekDaySaturday:
180 case iCalWeekDaySunday:
188 switch (self->frequency) {
189 case iCalRecurrenceFrequenceWeekly:
191 case iCalRecurrenceFrequenceMonthly:
193 case iCalRecurrenceFrequenceDaily:
195 case iCalRecurrenceFrequenceYearly:
197 case iCalRecurrenceFrequenceHourly:
199 case iCalRecurrenceFrequenceMinutely:
201 case iCalRecurrenceFrequenceSecondly:
204 return @"UNDEFINED?";
209 return [self iCalRepresentationForWeekDay:self->byDay.weekStart];
214 Each BYDAY value can also be preceded by a positive (+n) or negative
215 (-n) integer. If present, this indicates the nth occurrence of the
216 specific day within the MONTHLY or YEARLY RRULE. For example, within
217 a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday
218 within the month, whereas -1MO represents the last Monday of the
219 month. If an integer modifier is not present, it means all days of
220 this type within the specified frequency. For example, within a
221 MONTHLY rule, MO represents all Mondays within the month.
223 - (NSString *)byDayList {
225 unsigned i, mask, day;
228 s = [NSMutableString stringWithCapacity:20];
230 mask = self->byDay.mask;
231 day = iCalWeekDayMonday;
232 for (i = 0; i < 7; i++) {
235 [s appendString:@","];
236 [s appendString:[self iCalRepresentationForWeekDay:day]];
246 - (void)setRrule:(NSString *)_rrule {
247 ASSIGN(self->rrule, _rrule);
251 /* Processing existing rrule */
253 - (void)_processRule {
257 props = [self->rrule componentsSeparatedByString:@";"];
258 count = [props count];
259 for (i = 0; i < count; i++) {
260 NSString *prop, *key, *value;
263 prop = [props objectAtIndex:i];
264 r = [prop rangeOfString:@"="];
266 key = [prop substringToIndex:r.location];
267 value = [prop substringFromIndex:NSMaxRange(r)];
273 [self takeValue:value forKey:[key lowercaseString]];
280 - (void)setFreq:(NSString *)_freq {
281 _freq = [_freq uppercaseString];
282 if ([_freq isEqualToString:@"WEEKLY"])
283 self->frequency = iCalRecurrenceFrequenceWeekly;
284 else if ([_freq isEqualToString:@"MONTHLY"])
285 self->frequency = iCalRecurrenceFrequenceMonthly;
286 else if ([_freq isEqualToString:@"DAILY"])
287 self->frequency = iCalRecurrenceFrequenceDaily;
288 else if ([_freq isEqualToString:@"YEARLY"])
289 self->frequency = iCalRecurrenceFrequenceYearly;
290 else if ([_freq isEqualToString:@"HOURLY"])
291 self->frequency = iCalRecurrenceFrequenceHourly;
292 else if ([_freq isEqualToString:@"MINUTELY"])
293 self->frequency = iCalRecurrenceFrequenceMinutely;
294 else if ([_freq isEqualToString:@"SECONDLY"])
295 self->frequency = iCalRecurrenceFrequenceSecondly;
297 [NSException raise:NSGenericException
298 format:@"Incorrect frequency '%@' specified!", _freq];
301 - (void)setInterval:(NSString *)_interval {
302 self->interval = [_interval intValue];
304 - (void)setCount:(NSString *)_count {
305 self->repeatCount = [_count unsignedIntValue];
307 - (void)setUntil:(NSString *)_until {
309 NSCalendarDate *date;
311 dh = [[iCalDateHolder alloc] init];
312 [dh setString:_until];
313 date = [dh awakeAfterUsingSaxDecoder:nil];
314 ASSIGN(self->untilDate, date);
318 - (void)setWkst:(NSString *)_weekStart {
319 self->byDay.weekStart = [self weekDayFromICalRepresentation:_weekStart];
322 - (void)setByday:(NSString *)_byDayList {
326 self->byDay.mask = 0;
327 days = [_byDayList componentsSeparatedByString:@","];
328 count = [days count];
329 for (i = 0; i < count; i++) {
333 iCalDay = [days objectAtIndex:i];
334 day = [self weekDayFromICalRepresentation:iCalDay];
335 self->byDay.mask |= day;
339 /* key/value coding */
341 - (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
342 [self warnWithFormat:@"Don't know how to process '%@'!", _key];
348 - (NSString *)iCalRepresentation {
351 s = [NSMutableString stringWithCapacity:80];
352 [s appendString:@"FREQ="];
353 [s appendString:[self freq]];
354 if ([self repeatInterval] != 1) {
355 [s appendFormat:@";INTERVAL=%d", [self repeatInterval]];
357 if (![self isInfinite]) {
358 if ([self repeatCount] > 0) {
359 [s appendFormat:@";COUNT=%d", [self repeatCount]];
362 [s appendString:@";UNTIL="];
363 [s appendString:[[self untilDate] icalString]];
366 if (self->byDay.weekStart != iCalWeekDayMonday) {
367 [s appendString:@";WKST="];
368 [s appendString:[self iCalRepresentationForWeekDay:self->byDay.weekStart]];
370 if (self->byDay.mask != 0) {
371 [s appendString:@";BYDAY="];
372 [s appendString:[self byDayList]];