2007-01-31 18:11:29 +01:00
|
|
|
/*
|
|
|
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
|
|
|
|
|
|
This file is part of SOPE.
|
|
|
|
|
|
|
|
SOPE is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU Lesser General Public License as published by the
|
|
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
later version.
|
|
|
|
|
|
|
|
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
|
|
License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with SOPE; see the file COPYING. If not, write to the
|
|
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2007-02-08 17:27:00 +01:00
|
|
|
#import <Foundation/NSArray.h>
|
|
|
|
#import <Foundation/NSEnumerator.h>
|
2007-01-31 18:11:29 +01:00
|
|
|
#import <Foundation/NSException.h>
|
|
|
|
#import <NGExtensions/NSString+Ext.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
|
|
|
|
|
|
|
#import <ctype.h>
|
|
|
|
|
|
|
|
#import "NSCalendarDate+NGCards.h"
|
|
|
|
#import "NSString+NGCards.h"
|
|
|
|
|
|
|
|
#import "NSCalendarDate+ICal.h"
|
|
|
|
|
|
|
|
#import "iCalRecurrenceRule.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
freq = rrFreq;
|
|
|
|
until = rrUntil;
|
|
|
|
count = rrCount;
|
|
|
|
interval = rrInterval;
|
|
|
|
bysecond = rrBySecondList;
|
|
|
|
byminute = rrByMinuteList;
|
|
|
|
byhour = rrByHourList;
|
|
|
|
byday = rrByDayList;
|
|
|
|
bymonthday = rrByMonthDayList;
|
|
|
|
byyearday = rrByYearDayList;
|
|
|
|
byweekno = rrByWeekNumberList;
|
|
|
|
bymonth = rrByMonthList;
|
|
|
|
bysetpos = rrBySetPosList;
|
|
|
|
wkst = rrWeekStart;
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TODO: private API in the header file?!
|
|
|
|
@interface iCalRecurrenceRule (PrivateAPI)
|
|
|
|
|
|
|
|
- (iCalWeekDay) weekDayFromICalRepresentation: (NSString *) _day;
|
|
|
|
- (NSString *) iCalRepresentationForWeekDay: (iCalWeekDay) _waeekDay;
|
|
|
|
- (NSString *) freq;
|
|
|
|
- (NSString *) wkst;
|
|
|
|
- (NSString *) byDayList;
|
|
|
|
|
|
|
|
// - (void)_parseRuleString:(NSString *)_rrule;
|
|
|
|
|
|
|
|
/* currently used by parser, should be removed (replace with an -init..) */
|
|
|
|
- (void)setByday:(NSString *)_byDayList;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation iCalRecurrenceRule
|
|
|
|
|
|
|
|
+ (id) recurrenceRuleWithICalRepresentation: (NSString *) _iCalRep
|
|
|
|
{
|
2007-07-03 17:59:45 +02:00
|
|
|
iCalRecurrenceRule *rule;
|
|
|
|
|
|
|
|
rule = [self elementWithTag: @"rrule"];
|
|
|
|
if ([_iCalRep length] > 0)
|
|
|
|
[rule addValues: [_iCalRep componentsSeparatedByString: @";"]];
|
|
|
|
|
|
|
|
return rule;
|
2007-01-31 18:11:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if ((self = [super init]) != nil)
|
|
|
|
{
|
|
|
|
[self setTag: @"rrule"];
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithString: (NSString *) _str
|
|
|
|
{
|
|
|
|
if ((self = [self init]))
|
|
|
|
{
|
|
|
|
[self setRrule: _str];
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setRrule: (NSString *) _rrule
|
|
|
|
{
|
|
|
|
NSEnumerator *newValues;
|
|
|
|
NSString *newValue;
|
|
|
|
|
|
|
|
newValues = [[_rrule componentsSeparatedByString: @";"] objectEnumerator];
|
|
|
|
newValue = [newValues nextObject];
|
|
|
|
while (newValue)
|
|
|
|
{
|
|
|
|
[self addValue: newValue];
|
|
|
|
newValue = [newValues nextObject];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (iCalRecurrenceFrequency) valueForFrequency: (NSString *) value
|
|
|
|
{
|
|
|
|
NSString *frequency;
|
|
|
|
iCalRecurrenceFrequency freq;
|
|
|
|
|
2007-08-07 23:18:10 +02:00
|
|
|
if ([value length] > 0)
|
|
|
|
{
|
|
|
|
frequency = [value uppercaseString];
|
|
|
|
if ([frequency isEqualToString:@"WEEKLY"])
|
|
|
|
freq = iCalRecurrenceFrequenceWeekly;
|
|
|
|
else if ([frequency isEqualToString:@"MONTHLY"])
|
|
|
|
freq = iCalRecurrenceFrequenceMonthly;
|
|
|
|
else if ([frequency isEqualToString:@"DAILY"])
|
|
|
|
freq = iCalRecurrenceFrequenceDaily;
|
|
|
|
else if ([frequency isEqualToString:@"YEARLY"])
|
|
|
|
freq = iCalRecurrenceFrequenceYearly;
|
|
|
|
else if ([frequency isEqualToString:@"HOURLY"])
|
|
|
|
freq = iCalRecurrenceFrequenceHourly;
|
|
|
|
else if ([frequency isEqualToString:@"MINUTELY"])
|
|
|
|
freq = iCalRecurrenceFrequenceMinutely;
|
|
|
|
else if ([frequency isEqualToString:@"SECONDLY"])
|
|
|
|
freq = iCalRecurrenceFrequenceSecondly;
|
|
|
|
else
|
|
|
|
freq = NSNotFound;
|
|
|
|
}
|
2007-01-31 18:11:29 +01:00
|
|
|
else
|
|
|
|
freq = NSNotFound;
|
|
|
|
|
|
|
|
return freq;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) frequencyForValue: (iCalRecurrenceFrequency) freq
|
|
|
|
{
|
|
|
|
NSString *frequency;
|
|
|
|
|
|
|
|
switch (freq)
|
|
|
|
{
|
|
|
|
case iCalRecurrenceFrequenceWeekly:
|
|
|
|
frequency = @"WEEKLY";
|
|
|
|
break;
|
|
|
|
case iCalRecurrenceFrequenceMonthly:
|
|
|
|
frequency = @"MONTHLY";
|
|
|
|
break;
|
|
|
|
case iCalRecurrenceFrequenceDaily:
|
|
|
|
frequency = @"DAILY";
|
|
|
|
break;
|
|
|
|
case iCalRecurrenceFrequenceYearly:
|
|
|
|
frequency = @"YEARLY";
|
|
|
|
break;
|
|
|
|
case iCalRecurrenceFrequenceHourly:
|
|
|
|
frequency = @"HOURLY";
|
|
|
|
break;
|
|
|
|
case iCalRecurrenceFrequenceMinutely:
|
|
|
|
frequency = @"MINUTELY";
|
|
|
|
break;
|
|
|
|
case iCalRecurrenceFrequenceSecondly:
|
|
|
|
frequency = @"SECONDLY";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
frequency = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return frequency;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* accessors */
|
|
|
|
|
|
|
|
- (void) setFrequency: (iCalRecurrenceFrequency) _frequency
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"freq" to: [self frequencyForValue: _frequency]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (iCalRecurrenceFrequency) frequency
|
|
|
|
{
|
|
|
|
return [self valueForFrequency: [self namedValue: @"freq"]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setRepeatCount: (int) _repeatCount
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"count"
|
|
|
|
to: [NSString stringWithFormat: @"%d", _repeatCount]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (int) repeatCount
|
|
|
|
{
|
|
|
|
return [[self namedValue: @"count"] intValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setUntilDate: (NSCalendarDate *) _untilDate
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"until"
|
|
|
|
to: [_untilDate iCalFormattedDateTimeString]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSCalendarDate *) untilDate
|
|
|
|
{
|
|
|
|
#warning handling of default timezone needs to be implemented
|
|
|
|
return [[self namedValue: @"until"] asCalendarDate];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setInterval: (NSString *) _interval
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"interval" to: _interval];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setCount: (NSString *) _count
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"count" to: _count];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setUntil: (NSString *) _until
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"until" to: _until];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setRepeatInterval: (int) _repeatInterval
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"interval"
|
|
|
|
to: [NSString stringWithFormat: @"%d", _repeatInterval]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (int) repeatInterval
|
|
|
|
{
|
2008-01-23 04:44:51 +01:00
|
|
|
int interval;
|
|
|
|
|
|
|
|
interval = [[self namedValue: @"interval"] intValue];
|
|
|
|
if (interval < 1)
|
|
|
|
interval = 1;
|
|
|
|
|
|
|
|
return interval;
|
2007-01-31 18:11:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setWkst: (NSString *) _weekStart
|
|
|
|
{
|
|
|
|
[self setNamedValue: @"wkst" to: _weekStart];
|
|
|
|
}
|
|
|
|
|
2008-02-08 20:34:02 +01:00
|
|
|
#warning we also should handle the user weekstarts
|
2007-01-31 18:11:29 +01:00
|
|
|
- (NSString *) wkst
|
|
|
|
{
|
2008-02-08 20:34:02 +01:00
|
|
|
NSString *start;
|
|
|
|
|
|
|
|
start = [self namedValue: @"wkst"];
|
|
|
|
if (![start length])
|
2008-02-08 20:36:41 +01:00
|
|
|
start = @"MO";
|
2008-02-08 20:34:02 +01:00
|
|
|
|
|
|
|
return start;
|
2007-01-31 18:11:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setWeekStart: (iCalWeekDay) _weekStart
|
|
|
|
{
|
|
|
|
[self setWkst: [self iCalRepresentationForWeekDay: _weekStart]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (iCalWeekDay) weekStart
|
|
|
|
{
|
|
|
|
return [self weekDayFromICalRepresentation: [self wkst]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setByDayMask: (unsigned) _mask
|
|
|
|
{
|
|
|
|
NSMutableArray *days;
|
|
|
|
unsigned int count;
|
2008-03-10 05:48:28 +01:00
|
|
|
unsigned char maskDays[] = { iCalWeekDaySunday, iCalWeekDayMonday,
|
|
|
|
iCalWeekDayTuesday, iCalWeekDayWednesday,
|
|
|
|
iCalWeekDayThursday, iCalWeekDayFriday,
|
|
|
|
iCalWeekDaySaturday };
|
2007-01-31 18:11:29 +01:00
|
|
|
days = [NSMutableArray arrayWithCapacity: 7];
|
|
|
|
if (_mask)
|
|
|
|
{
|
|
|
|
for (count = 0; count < 7; count++)
|
|
|
|
if (_mask & maskDays[count])
|
|
|
|
[days addObject:
|
|
|
|
[self iCalRepresentationForWeekDay: maskDays[count]]];
|
|
|
|
}
|
|
|
|
|
|
|
|
[self setNamedValue: @"byday" to: [days componentsJoinedByString: @","]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned int) byDayMask
|
|
|
|
{
|
|
|
|
NSArray *days;
|
|
|
|
unsigned int mask, count, max;
|
2007-08-07 23:18:10 +02:00
|
|
|
NSString *day, *value;
|
2007-01-31 18:11:29 +01:00
|
|
|
|
|
|
|
mask = 0;
|
|
|
|
|
2007-08-07 23:18:10 +02:00
|
|
|
value = [self namedValue: @"byday"];
|
|
|
|
if ([value length] > 0)
|
2007-01-31 18:11:29 +01:00
|
|
|
{
|
2007-08-07 23:18:10 +02:00
|
|
|
days = [value componentsSeparatedByString: @","];
|
|
|
|
max = [days count];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
day = [days objectAtIndex: count];
|
|
|
|
mask |= [self weekDayFromICalRepresentation: day];
|
|
|
|
}
|
2007-01-31 18:11:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
2007-07-03 17:59:45 +02:00
|
|
|
#warning this is bad
|
2007-01-31 18:11:29 +01:00
|
|
|
- (int) byDayOccurence1
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
// return byDayOccurence1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) byMonthDay
|
|
|
|
{
|
2008-03-26 21:30:53 +01:00
|
|
|
NSArray *byMonthDay;
|
|
|
|
NSString *byMonthDayStr;
|
|
|
|
|
|
|
|
byMonthDayStr = [self namedValue: @"bymonthday"];
|
|
|
|
if ([byMonthDayStr length])
|
|
|
|
byMonthDay = [byMonthDayStr componentsSeparatedByString: @","];
|
|
|
|
else
|
|
|
|
byMonthDay = nil;
|
|
|
|
|
|
|
|
return byMonthDay;
|
2007-01-31 18:11:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isInfinite
|
|
|
|
{
|
|
|
|
return !([self repeatCount] || [self untilDate]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* private */
|
|
|
|
|
|
|
|
- (iCalWeekDay) weekDayFromICalRepresentation: (NSString *) _day
|
|
|
|
{
|
2008-01-28 19:51:52 +01:00
|
|
|
/* be tolerant */
|
|
|
|
iCalWeekDay foundDay;
|
|
|
|
unichar chars[2];
|
2008-01-28 19:57:08 +01:00
|
|
|
unsigned int dayLength;
|
2008-01-28 19:51:52 +01:00
|
|
|
|
|
|
|
foundDay = 0;
|
|
|
|
|
2008-01-28 19:57:08 +01:00
|
|
|
dayLength = [_day length];
|
|
|
|
if (dayLength > 1)
|
2008-01-28 19:51:52 +01:00
|
|
|
{
|
|
|
|
[[_day uppercaseString] getCharacters: chars
|
2008-01-28 19:57:08 +01:00
|
|
|
range: NSMakeRange (dayLength - 2, 2)];
|
2008-01-28 19:51:52 +01:00
|
|
|
|
|
|
|
switch (chars[0])
|
|
|
|
{
|
|
|
|
case 'M': foundDay = iCalWeekDayMonday;
|
|
|
|
break;
|
|
|
|
case 'W': foundDay = iCalWeekDayWednesday;
|
|
|
|
break;
|
|
|
|
case 'F': foundDay = iCalWeekDayFriday;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
if (chars[1] == 'U')
|
|
|
|
foundDay = iCalWeekDayTuesday;
|
|
|
|
else if (chars[1] == 'H')
|
|
|
|
foundDay = iCalWeekDayThursday;
|
2008-03-26 21:30:53 +01:00
|
|
|
break;
|
2008-01-28 19:51:52 +01:00
|
|
|
case 'S':
|
|
|
|
if (chars[1] == 'A')
|
|
|
|
foundDay = iCalWeekDaySaturday;
|
2008-02-08 20:34:02 +01:00
|
|
|
else if (chars[1] == 'U')
|
2008-01-28 19:51:52 +01:00
|
|
|
foundDay = iCalWeekDaySunday;
|
2008-03-26 21:30:53 +01:00
|
|
|
break;
|
2008-01-28 19:51:52 +01:00
|
|
|
}
|
2007-01-31 18:11:29 +01:00
|
|
|
}
|
2007-07-03 17:59:45 +02:00
|
|
|
|
2008-01-28 19:51:52 +01:00
|
|
|
if (!foundDay)
|
|
|
|
[self errorWithFormat: @"wrong weekday representation: '%@'", _day];
|
|
|
|
|
|
|
|
return foundDay;
|
2007-07-03 17:59:45 +02:00
|
|
|
// // TODO: do not raise but rather return an error value?
|
|
|
|
// [NSException raise:NSGenericException
|
|
|
|
// format:@"Incorrect weekDay '%@' specified!", _day];
|
|
|
|
// return iCalWeekDayMonday; /* keep compiler happy */
|
2007-01-31 18:11:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) iCalRepresentationForWeekDay: (iCalWeekDay) _weekDay
|
|
|
|
{
|
|
|
|
switch (_weekDay)
|
|
|
|
{
|
|
|
|
case iCalWeekDayMonday: return @"MO";
|
|
|
|
case iCalWeekDayTuesday: return @"TU";
|
|
|
|
case iCalWeekDayWednesday: return @"WE";
|
|
|
|
case iCalWeekDayThursday: return @"TH";
|
|
|
|
case iCalWeekDayFriday: return @"FR";
|
|
|
|
case iCalWeekDaySaturday: return @"SA";
|
|
|
|
case iCalWeekDaySunday: return @"SU";
|
|
|
|
default: return @"MO"; // TODO: return error?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - (iCalWeekDay) weekDayForiCalRepre: (NSString *) _weekDay
|
|
|
|
// {
|
|
|
|
// iCalWeekDay day;
|
|
|
|
// NSString *weekDay;
|
|
|
|
|
|
|
|
// weekDay = [_weekDay uppercaseString];
|
|
|
|
// if ([weekDay isEqualToString: @"TU"])
|
|
|
|
// day = iCalWeekDayTuesday;
|
|
|
|
// else if ([weekDay isEqualToString: @"WE"])
|
|
|
|
// day = iCalWeekDayWednesday;
|
|
|
|
// else if ([weekDay isEqualToString: @"TH"])
|
|
|
|
// day = iCalWeekDayThursday;
|
|
|
|
// else if ([weekDay isEqualToString: @"FR"])
|
|
|
|
// day = iCalWeekDayFriday;
|
|
|
|
// else if ([weekDay isEqualToString: @"SA"])
|
|
|
|
// day = iCalWeekDaySaturday;
|
|
|
|
// else if ([weekDay isEqualToString: @"SU"])
|
|
|
|
// day = iCalWeekDaySunday;
|
|
|
|
// else
|
|
|
|
// day = iCalWeekDayMonday;
|
|
|
|
|
|
|
|
// return day;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// - (NSString *) wkst
|
|
|
|
// {
|
|
|
|
// return [self iCalRepresentationForWeekDay:byDay.weekStart];
|
|
|
|
// }
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO:
|
|
|
|
Each BYDAY value can also be preceded by a positive (+n) or negative
|
|
|
|
(-n) integer. If present, this indicates the nth occurrence of the
|
|
|
|
specific day within the MONTHLY or YEARLY RRULE. For example, within
|
|
|
|
a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday
|
|
|
|
within the month, whereas -1MO represents the last Monday of the
|
|
|
|
month. If an integer modifier is not present, it means all days of
|
|
|
|
this type within the specified frequency. For example, within a
|
|
|
|
MONTHLY rule, MO represents all Mondays within the month.
|
|
|
|
*/
|
|
|
|
// - (NSString *) byDayList
|
|
|
|
// {
|
|
|
|
// NSMutableString *s;
|
|
|
|
// unsigned dow, mask, day;
|
|
|
|
// BOOL needsComma;
|
|
|
|
|
|
|
|
// s = [NSMutableString stringWithCapacity:20];
|
|
|
|
// needsComma = NO;
|
|
|
|
// mask = byDay.mask;
|
|
|
|
// day = iCalWeekDayMonday;
|
|
|
|
|
|
|
|
// for (dow = 0 /* Sun */; dow < 7; dow++) {
|
|
|
|
// if (mask & day) {
|
|
|
|
// if (needsComma)
|
|
|
|
// [s appendString:@","];
|
|
|
|
|
|
|
|
// if (byDay.useOccurence)
|
|
|
|
// // Note: we only support one occurrence for all currently
|
|
|
|
// [s appendFormat:@"%i", byDayOccurence1];
|
|
|
|
|
|
|
|
// [s appendString:[self iCalRepresentationForWeekDay:day]];
|
|
|
|
// needsComma = YES;
|
|
|
|
// }
|
|
|
|
// day = (day << 1);
|
|
|
|
// }
|
|
|
|
|
|
|
|
// return s;
|
|
|
|
// }
|
|
|
|
|
|
|
|
/* parsing rrule */
|
|
|
|
|
|
|
|
// - (void) _parseRuleString: (NSString *) _rrule
|
|
|
|
// {
|
|
|
|
// // TODO: to be exact we would need a timezone to properly process the 'until'
|
|
|
|
// // date
|
|
|
|
// unsigned i, count;
|
|
|
|
// NSString *pFrequency = nil;
|
|
|
|
// NSString *pUntil = nil;
|
|
|
|
// NSString *pCount = nil;
|
|
|
|
// NSString *pByday = nil;
|
|
|
|
// NSString *pBymday = nil;
|
|
|
|
// NSString *pBysetpos = nil;
|
|
|
|
// NSString *pInterval = nil;
|
|
|
|
|
|
|
|
// for (i = 0, count = [values count]; i < count; i++) {
|
|
|
|
// NSString *prop, *key, *value;
|
|
|
|
// NSRange r;
|
|
|
|
// NSString **vHolder = NULL;
|
|
|
|
|
|
|
|
// prop = [values objectAtIndex:i];
|
|
|
|
// r = [prop rangeOfString:@"="];
|
|
|
|
// if (r.length > 0) {
|
|
|
|
// key = [prop substringToIndex:r.location];
|
|
|
|
// value = [prop substringFromIndex:NSMaxRange(r)];
|
|
|
|
// }
|
|
|
|
// else {
|
|
|
|
// key = prop;
|
|
|
|
// value = nil;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// key = [[key stringByTrimmingSpaces] lowercaseString];
|
|
|
|
// if (![key isNotEmpty]) {
|
|
|
|
// [self errorWithFormat:@"empty component in rrule: %@", _rrule];
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// vHolder = NULL;
|
|
|
|
// switch ([key characterAtIndex:0]) {
|
|
|
|
// case 'b':
|
|
|
|
// if ([key isEqualToString:@"byday"]) { vHolder = &pByday; break; }
|
|
|
|
// if ([key isEqualToString:@"bymonthday"]) { vHolder = &pBymday; break; }
|
|
|
|
// if ([key isEqualToString:@"bysetpos"]) { vHolder = &pBysetpos; break; }
|
|
|
|
// break;
|
|
|
|
// case 'c':
|
|
|
|
// if ([key isEqualToString:@"count"]) { vHolder = &pCount; break; }
|
|
|
|
// break;
|
|
|
|
// case 'f':
|
|
|
|
// if ([key isEqualToString:@"freq"]) { vHolder = &pFrequency; break; }
|
|
|
|
// break;
|
|
|
|
// case 'i':
|
|
|
|
// if ([key isEqualToString:@"interval"]) { vHolder = &pInterval; break; }
|
|
|
|
// break;
|
|
|
|
// case 'u':
|
|
|
|
// if ([key isEqualToString:@"until"]) { vHolder = &pUntil; break; }
|
|
|
|
// break;
|
|
|
|
// default:
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if (vHolder != NULL) {
|
|
|
|
// if ([*vHolder isNotEmpty])
|
|
|
|
// [self errorWithFormat:@"more than one '%@' in: %@", key, _rrule];
|
|
|
|
// else
|
|
|
|
// *vHolder = [value copy];
|
|
|
|
// }
|
|
|
|
// else {
|
|
|
|
// // TODO: we should just parse known keys and put remainders into a
|
|
|
|
// // separate dictionary
|
|
|
|
// [self logWithFormat:@"TODO: add explicit support for key: %@", key];
|
|
|
|
// [self takeValue:value forKey:key];
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// /* parse and fill individual values */
|
|
|
|
// // TODO: this method should be a class method and create a new rrule object
|
|
|
|
|
|
|
|
// if ([pFrequency isNotEmpty])
|
|
|
|
// [self setNamedValue: @"FREQ" to: pFrequency];
|
|
|
|
// else
|
|
|
|
// [self errorWithFormat:@"rrule contains no frequency: '%@'", _rrule];
|
|
|
|
// [pFrequency release]; pFrequency = nil;
|
|
|
|
|
|
|
|
// if (pInterval != nil)
|
|
|
|
// interval = [pInterval intValue];
|
|
|
|
// [pInterval release]; pInterval = nil;
|
|
|
|
|
|
|
|
// // TODO: we should parse byday in here
|
|
|
|
// if (pByday != nil) [self setByday:pByday];
|
|
|
|
// [pByday release]; pByday = nil;
|
|
|
|
|
|
|
|
// if (pBymday != nil) {
|
|
|
|
// NSArray *t;
|
|
|
|
|
|
|
|
// t = [pBymday componentsSeparatedByString:@","];
|
|
|
|
// ASSIGNCOPY(byMonthDay, t);
|
|
|
|
// }
|
|
|
|
// [pBymday release]; pBymday = nil;
|
|
|
|
|
|
|
|
// if (pBysetpos != nil)
|
|
|
|
// // TODO: implement
|
|
|
|
// [self errorWithFormat:@"rrule contains bysetpos, unsupported: %@", _rrule];
|
|
|
|
// [pBysetpos release]; pBysetpos = nil;
|
|
|
|
|
|
|
|
// if (pUntil != nil) {
|
|
|
|
// NSCalendarDate *pUntilDate;
|
|
|
|
|
|
|
|
// if (pCount != nil) {
|
|
|
|
// [self errorWithFormat:@"rrule contains 'count' AND 'until': %@", _rrule];
|
|
|
|
// [pCount release];
|
|
|
|
// pCount = nil;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// /*
|
|
|
|
// The spec says:
|
|
|
|
// "If specified as a date-time value, then it MUST be specified in an
|
|
|
|
// UTC time format."
|
|
|
|
// TODO: we still need some object representing a 'timeless' date.
|
|
|
|
// */
|
|
|
|
// if (![pUntil hasSuffix:@"Z"] && [pUntil length] > 8) {
|
|
|
|
// [self warnWithFormat:@"'until' date has no explicit UTC marker: '%@'",
|
|
|
|
// _rrule];
|
|
|
|
// }
|
|
|
|
|
|
|
|
// pUntilDate = [NSCalendarDate calendarDateWithICalRepresentation:pUntil];
|
|
|
|
// if (pUntilDate != nil)
|
|
|
|
// [self setUntilDate:pUntilDate];
|
|
|
|
// else {
|
|
|
|
// [self errorWithFormat:@"could not parse 'until' in rrule: %@",
|
|
|
|
// _rrule];
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// [pUntil release]; pUntil = nil;
|
|
|
|
|
|
|
|
// if (pCount != nil)
|
|
|
|
// [self setRepeatCount:[pCount intValue]];
|
|
|
|
// [pCount release]; pCount = nil;
|
|
|
|
// }
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
|
|
|
|
// - (void) setByday: (NSString *) _byDayList
|
|
|
|
// {
|
|
|
|
// // TODO: each day can have an associated occurence, eg:
|
|
|
|
// // +1MO,+2TU,-9WE
|
|
|
|
// // TODO: this should be moved to the parser
|
|
|
|
// NSArray *days;
|
|
|
|
// unsigned i, count;
|
|
|
|
// NSString *iCalDay;
|
|
|
|
// iCalWeekDay day;
|
|
|
|
// unsigned len;
|
|
|
|
// unichar c0;
|
|
|
|
// int occurence;
|
|
|
|
// int offset;
|
|
|
|
|
|
|
|
// /* reset mask */
|
|
|
|
// byDay.mask = 0;
|
|
|
|
// byDay.useOccurence = 0;
|
|
|
|
// byDayOccurence1 = 0;
|
|
|
|
|
|
|
|
// days = [_byDayList componentsSeparatedByString:@","];
|
|
|
|
// for (i = 0, count = [days count]; i < count; i++)
|
|
|
|
// {
|
|
|
|
// iCalDay = [days objectAtIndex:i]; // eg: MO or TU
|
|
|
|
// if ((len = [iCalDay length]) == 0)
|
|
|
|
// {
|
|
|
|
// [self errorWithFormat:@"found an empty day in byday list: '%@'",
|
|
|
|
// _byDayList];
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// c0 = [iCalDay characterAtIndex:0];
|
|
|
|
// if (((c0 == '+' || c0 == '-') && len > 2) || (isdigit(c0) && len > 1)) {
|
|
|
|
// occurence = [iCalDay intValue];
|
|
|
|
|
|
|
|
// offset = 1; /* skip occurence */
|
|
|
|
// while (offset < len && isdigit([iCalDay characterAtIndex:offset]))
|
|
|
|
// offset++;
|
|
|
|
|
|
|
|
// iCalDay = [iCalDay substringFromIndex:offset];
|
|
|
|
|
|
|
|
// if (byDay.useOccurence && (occurence != byDayOccurence1))
|
|
|
|
// {
|
|
|
|
// [self errorWithFormat:
|
|
|
|
// @"we only supported one occurence (occ=%i,day=%@): '%@'",
|
|
|
|
// occurence, iCalDay, _byDayList];
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// byDay.useOccurence = 1;
|
|
|
|
// byDayOccurence1 = occurence;
|
|
|
|
// }
|
|
|
|
// else if (byDay.useOccurence)
|
|
|
|
// [self errorWithFormat:
|
|
|
|
// @"a byday occurence was specified on one day, but not on others"
|
|
|
|
// @" (unsupported): '%@'", _byDayList];
|
|
|
|
|
|
|
|
// day = [self weekDayFromICalRepresentation:iCalDay];
|
|
|
|
// byDay.mask |= day;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
/* key/value coding */
|
|
|
|
|
|
|
|
- (void) handleTakeValue: (id) _value
|
|
|
|
forUnboundKey: (NSString *)_key
|
|
|
|
{
|
|
|
|
[self warnWithFormat:@"Cannot handle unbound key: '%@'", _key];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end /* iCalRecurrenceRule */
|