+2005-02-17 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.44
+
+ * iCalEntityObject.[hm]: added convenience API
+
+ * iCalRepeatableEntityObject.[hm]: added convenience API
+
+ * iCalRecurrenceRule.m: bugfixes in -byDayList and
+ -iCalRepresentationForWeekDay:
+
+ * iCalRecurrenceCalculator.m: implemented 'BYDAY' calculations for
+ weekly frequency. Note that 'COUNT' is still broken for this case.
+
+ * iCalRenderer.m: updated rendering, now can render recurrence rules
+ and accompanied stuff properly.
+
2005-02-15 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.43
sourceTree = "<group>";
};
ADAACE6707B3973900FC48D6 = {
- fileEncoding = 4;
+ fileEncoding = 5;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.objc;
path = iCalRecurrenceCalculator.m;
);
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 4.5.43;
+ DYLIB_CURRENT_VERSION = 4.5.44;
FRAMEWORK_SEARCH_PATHS = "\"$(USER_LIBRARY_DIR)/EmbeddedFrameworks\"";
FRAMEWORK_VERSION = A;
GCC_PRECOMPILE_PREFIX_HEADER = NO;
);
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 4.5.43;
+ DYLIB_CURRENT_VERSION = 4.5.44;
FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
FRAMEWORK_VERSION = A;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
MAJOR_VERSION=4
MINOR_VERSION=5
-SUBMINOR_VERSION:=43
+SUBMINOR_VERSION:=44
# v4.5.40 requires NGExtensions v4.5.145
# v4.5.37 requires NGExtensions v4.5.140
- (void)setOrganizer:(iCalPerson *)_organizer;
- (iCalPerson *)organizer;
+- (BOOL)isOrganizer:(id)_email;
- (void)setStatus:(NSString *)_value;
- (NSString *)status;
- (void)addToAttendees:(iCalPerson *)_person;
- (NSArray *)attendees;
+/* categorize attendees into participants and resources */
+- (NSArray *)participants;
+- (NSArray *)resources;
+- (BOOL)isParticipant:(id)_email;
+- (iCalPerson *)findParticipantWithEmail:(id)_email;
+
- (void)removeAllAlarms;
- (void)addToAlarms:(id)_alarm;
- (NSArray *)alarms;
#include "iCalPerson.h"
#include "common.h"
+@interface iCalEntityObject (PrivateAPI)
+- (NSArray *)_filteredAttendeesThinkingOfPersons:(BOOL)_persons;
+@end
@implementation iCalEntityObject
return self->alarms;
}
+/* stuff */
+
+- (NSArray *)participants {
+ return [self _filteredAttendeesThinkingOfPersons:YES];
+}
+- (NSArray *)resources {
+ return [self _filteredAttendeesThinkingOfPersons:NO];
+}
+
+- (NSArray *)_filteredAttendeesThinkingOfPersons:(BOOL)_persons {
+ NSArray *list;
+ NSMutableArray *filtered;
+ unsigned i, count;
+
+ list = [self attendees];
+ count = [list count];
+ filtered = [NSMutableArray arrayWithCapacity:count];
+ for (i = 0; i < count; i++) {
+ iCalPerson *p;
+ NSString *role;
+
+ p = [list objectAtIndex:i];
+ role = [p role];
+ if (_persons) {
+ if (role == nil || ![role hasPrefix:@"NON-PART"])
+ [filtered addObject:p];
+ }
+ else {
+ if ([role hasPrefix:@"NON-PART"])
+ [filtered addObject:p];
+ }
+ }
+ return filtered;
+}
+
+- (BOOL)isOrganizer:(id)_email {
+ return [[[self organizer] rfc822Email] isEqualToString:_email];
+}
+
+- (BOOL)isParticipant:(id)_email {
+ NSArray *partEmails;
+
+ partEmails = [[self participants] valueForKey:@"rfc822Email"];
+ return [partEmails containsObject:_email];
+}
+
+- (iCalPerson *)findParticipantWithEmail:(id)_email {
+ NSArray *ps;
+ unsigned i, count;
+
+ ps = [self participants];
+ count = [ps count];
+
+ for (i = 0; i < count; i++) {
+ iCalPerson *p;
+
+ p = [ps objectAtIndex:i];
+ if ([[p rfc822Email] isEqualToString:_email])
+ return p;
+ }
+ return nil; /* not found */
+}
+
@end /* iCalEntityObject */
@interface iCalRecurrenceCalculator (PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
+
+- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
+- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
+- (unsigned)offsetFromSundayForCurrentWeekStart;
+
+- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
@end
@implementation iCalRecurrenceCalculator
return self;
}
+/* helpers */
+
+- (unsigned)offsetFromSundayForJulianNumber:(long)_jn {
+ return (unsigned)((int)(_jn + 1.5)) % 7;
+}
+
+- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay {
+ unsigned offset;
+
+ switch (_weekDay) {
+ case iCalWeekDaySunday: offset = 0; break;
+ case iCalWeekDayMonday: offset = 1; break;
+ case iCalWeekDayTuesday: offset = 2; break;
+ case iCalWeekDayWednesday: offset = 3; break;
+ case iCalWeekDayThursday: offset = 4; break;
+ case iCalWeekDayFriday: offset = 5; break;
+ case iCalWeekDaySaturday: offset = 6; break;
+ default: offset = 0; break;
+ }
+ return offset;
+}
+
+- (unsigned)offsetFromSundayForCurrentWeekStart {
+ return [self offsetFromSundayForWeekDay:[self->rrule weekStart]];
+}
+
+- (iCalWeekDay)weekDayForJulianNumber:(long)_jn {
+ unsigned day;
+ iCalWeekDay weekDay;
+
+ day = [self offsetFromSundayForJulianNumber:_jn];
+ switch (day) {
+ case 0: weekDay = iCalWeekDaySunday; break;
+ case 1: weekDay = iCalWeekDayMonday; break;
+ case 2: weekDay = iCalWeekDayTuesday; break;
+ case 3: weekDay = iCalWeekDayWednesday; break;
+ case 4: weekDay = iCalWeekDayThursday; break;
+ case 5: weekDay = iCalWeekDayFriday; break;
+ case 6: weekDay = iCalWeekDaySaturday; break;
+ default: weekDay = iCalWeekDaySunday; break; /* keep compiler happy */
+ }
+ return weekDay;
+}
/* calculation */
}
}
else {
- [self errorWithFormat:@"Cannot calculate rules with byDayMask, yet!"];
+ long jnFirstWeekStart, weekStartOffset;
+
+ /* calculate jnFirst's week start - this depends on our setting of week
+ start */
+ weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] -
+ [self offsetFromSundayForCurrentWeekStart];
+
+ jnFirstWeekStart = jnFirst - weekStartOffset;
+
+ for (i = 0 ; i < startEndCount; i++) {
+ long jnCurrent;
+
+ jnCurrent = jnStart + i;
+ if (jnCurrent >= jnFirst) {
+ long jnDiff;
+
+ /* we need to calculate a difference in weeks */
+ jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
+ if ((jnDiff % interval) == 0) {
+ BOOL isRecurrence = NO;
+
+ if (jnCurrent == jnFirst) {
+ isRecurrence = YES;
+ }
+ else {
+ iCalWeekDay weekDay;
+
+ weekDay = [self weekDayForJulianNumber:jnCurrent];
+ isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO;
+ }
+ if (isRecurrence) {
+ NSCalendarDate *start, *end;
+ NGCalendarDateRange *r;
+
+ start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ start = [start hour: [firStart hourOfDay]
+ minute:[firStart minuteOfHour]
+ second:[firStart secondOfMinute]];
+ end = [start addTimeInterval:[self->firstRange duration]];
+ r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
+ endDate:end];
+ [ranges addObject:r];
+ }
+ }
+ }
+ }
}
return ranges;
}
ranges = [NSMutableArray arrayWithCapacity:count];
for (i = 0 ; i < count; i++) {
unsigned test;
-
+
test = diff + i;
if ((test % interval) == 0) {
NSCalendarDate *start, *end;
}
- (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay {
- switch (self->byDay.weekStart) {
+ switch (_weekDay) {
case iCalWeekDayMonday:
return @"MO";
case iCalWeekDayTuesday:
*/
- (NSString *)byDayList {
NSMutableString *s;
- unsigned i, day;
+ unsigned i, mask, day;
BOOL needsComma;
s = [NSMutableString stringWithCapacity:20];
needsComma = NO;
+ mask = self->byDay.mask;
day = iCalWeekDayMonday;
-
for (i = 0; i < 7; i++) {
- if (self->byDay.mask && day) {
+ if (mask & day) {
if (needsComma)
[s appendString:@","];
[s appendString:[self iCalRepresentationForWeekDay:day]];
needsComma = YES;
}
- day = day << 1;
+ day = (day << 1);
}
return s;
}
#include "iCalRenderer.h"
#include "iCalEvent.h"
#include "iCalPerson.h"
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
#include "common.h"
-@interface NSDate(UsedPrivates)
-- (NSString *)icalString; // declared in NGiCal
-@end
-
@implementation iCalRenderer
static iCalRenderer *renderer = nil;
[s appendString:@";"];
}
+ if ((x = [p partStat])) {
+ if ([p participationStatus] != iCalPersonPartStatNeedsAction) {
+ [s appendString:@"PARTSTAT="];
+ [s appendString:[x iCalSafeString]];
+ [s appendString:@";"];
+ }
+ }
+
[s appendString:@"CN=\""];
- if ((x = [p cn])) {
+ if ((x = [p cnWithoutQuotes])) {
[s appendString:[x iCalDQUOTESafeString]];
}
[s appendString:@"\""];
[s appendString:@"\r\n"];
}
-
- /* what's all this? */
- [s appendString:@"TRANSP:OPAQUE\r\n"]; /* transparency */
- [s appendString:@"CLASS:PRIVATE\r\n"]; /* classification [like 'top secret'] */
-
+ if ((tmp = [event transparency]) != nil) {
+ [s appendString:@"TRANSP:"];
+ [s appendString:tmp];
+ [s appendString:@"\r\n"];
+ }
+
+ [s appendString:@"CLASS:"];
+ [s appendString:[event accessClass]];
+ [s appendString:@"\r\n"];
+
+ /* recurrence rules */
+ if ([event hasRecurrenceRules]) {
+ NSArray *rules;
+ unsigned i, count;
+
+ rules = [event recurrenceRules];
+ count = [rules count];
+ for (i = 0; i < count; i++) {
+ iCalRecurrenceRule *rule;
+
+ rule = [rules objectAtIndex:i];
+ [s appendString:@"RRULE:"];
+ [s appendString:[rule iCalRepresentation]];
+ [s appendString:@"\r\n"];
+ }
+ }
+
+ /* exception rules */
+ if ([event hasExceptionRules]) {
+ NSArray *rules;
+ unsigned i, count;
+
+ rules = [event exceptionRules];
+ count = [rules count];
+ for (i = 0; i < count; i++) {
+ iCalRecurrenceRule *rule;
+
+ rule = [rules objectAtIndex:i];
+ [s appendString:@"EXRULE:"];
+ [s appendString:[rule iCalRepresentation]];
+ [s appendString:@"\r\n"];
+ }
+ }
+
+ /* exception dates */
+ if ([event hasExceptionDates]) {
+ NSArray *dates;
+ unsigned i, count;
+
+ dates = [event exceptionDates];
+ count = [dates count];
+ [s appendString:@"EXDATE:"];
+ for (i = 0; i < count; i++) {
+ if (i > 0)
+ [s appendString:@","];
+ [s appendString:[[dates objectAtIndex:i] icalString]];
+ }
+ [s appendString:@"\r\n"];
+ }
+
[self addOrganizer:[event organizer] toString:s];
[self addAttendees:[event attendees] toString:s];
return NO;
if ([[_apt uid] length] == 0) {
- [self logWithFormat:
- @"WARNING: got apt without uid, rejecting iCal generation: %@",
- _apt];
+ [self warnWithFormat:@"got apt without uid, rejecting iCal generation: %@",
+ _apt];
return NO;
}
if ([[[_apt startDate] icalString] length] == 0) {
- [self logWithFormat:
- @"WARNING: got apt without start date, "
- @"rejecting iCal generation: %@",
- _apt];
+ [self warnWithFormat:@"got apt without start date, "
+ @"rejecting iCal generation: %@",
+ _apt];
return NO;
}
- (void)removeAllExceptionDates;
- (void)addToExceptionDates:(id)_date;
+- (BOOL)hasExceptionDates;
- (NSArray *)exceptionDates;
- (BOOL)isRecurrent;
self->exDates = [[NSMutableArray alloc] initWithCapacity:4];
[self->exDates addObject:_date];
}
+- (BOOL)hasExceptionDates {
+ return [self->exDates count] > 0 ? YES : NO;
+}
- (NSArray *)exceptionDates {
return self->exDates;
}