]> err.no Git - sope/commitdiff
various fixes and improvements
authorznek <znek@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Thu, 17 Feb 2005 18:33:06 +0000 (18:33 +0000)
committerznek <znek@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Thu, 17 Feb 2005 18:33:06 +0000 (18:33 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@570 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-ical/NGiCal/ChangeLog
sope-ical/NGiCal/NGiCal.xcode/project.pbxproj
sope-ical/NGiCal/Version
sope-ical/NGiCal/iCalEntityObject.h
sope-ical/NGiCal/iCalEntityObject.m
sope-ical/NGiCal/iCalRecurrenceCalculator.m
sope-ical/NGiCal/iCalRecurrenceRule.m
sope-ical/NGiCal/iCalRenderer.m
sope-ical/NGiCal/iCalRepeatableEntityObject.h
sope-ical/NGiCal/iCalRepeatableEntityObject.m

index 1ac9c8712e5746c681f8472e1dc78c670a5cf164..9ecb46a777f66e91fa54d7cc840fa1edd6e4d006 100644 (file)
@@ -1,3 +1,20 @@
+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
index fffebc1d721641dd5229b086947ca3a287a944f9..260e7a10a77d8edfc11ce3d2d8ce094146b93f7f 100644 (file)
@@ -86,7 +86,7 @@
                        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;
index 116461db6eb45ca2d360a272c0f15c5e7c9029cd..9732ed14bc380c9f90b550e7df210d1eaa9553c3 100644 (file)
@@ -2,7 +2,7 @@
 
 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
index 769230faa62026eb5ce3a8dd144b803067b8fe0e..64a14ea4489e2b2daae1ee8c7c68c9b34c4e0ca7 100644 (file)
@@ -94,6 +94,7 @@
 
 - (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;
index 4700626bd9465fae1eb4d41138737075c58e740b..2d45b784ffe40fa805e4f519c964e685b9be11db 100644 (file)
@@ -23,6 +23,9 @@
 #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 */
index 7878d45bcc6aa2ec3d049b382709e7c30c13b74d..2931f5a67c8a944709b12b9f359069158c51c52b 100644 (file)
 
 @interface iCalRecurrenceCalculator (PrivateAPI)
 - (NSCalendarDate *)lastInstanceStartDate;
+
+- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
+- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
+- (unsigned)offsetFromSundayForCurrentWeekStart;
+  
+- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
 @end
 
 @implementation iCalRecurrenceCalculator
@@ -105,6 +111,49 @@ static Class yearlyCalcClass  = Nil;
   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 */
 
@@ -311,7 +360,52 @@ static Class yearlyCalcClass  = Nil;
     }
   }
   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;
 }
@@ -422,7 +516,7 @@ static Class yearlyCalcClass  = Nil;
   ranges = [NSMutableArray arrayWithCapacity:count];
   for (i = 0 ; i < count; i++) {
     unsigned test;
-    
+
     test = diff + i;
     if ((test % interval) == 0) {
       NSCalendarDate      *start, *end;
index 4665b064e91c9a49f3c380c9b26a59e87f4aa572..7c09525fdb2c23aff6bae64b52323d39cae033bf 100644 (file)
 }
 
 - (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;
 }
index 35361299d5e2548a0578a90e522f2656be6a0d44..c7e108afbc8d9036b24d551b6fb4de2a006f4f95 100644 (file)
 #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;
@@ -91,8 +89,16 @@ static unsigned DefaultICalStringCapacity = 1024;
       [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:@"\""];
@@ -165,11 +171,66 @@ static unsigned DefaultICalStringCapacity = 1024;
     [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];
   
@@ -182,16 +243,14 @@ static unsigned DefaultICalStringCapacity = 1024;
     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;
   }
   
index a57c01a6abf8a3c40397f4ec37481f92ba241426..a8cc1c1e8a04b548f122ca1f0f10881c9730fbe5 100644 (file)
@@ -53,6 +53,7 @@
 
 - (void)removeAllExceptionDates;
 - (void)addToExceptionDates:(id)_date;
+- (BOOL)hasExceptionDates;
 - (NSArray *)exceptionDates;
 
 - (BOOL)isRecurrent;
index 00f9fae7a271190b5dda0db63d16b802a43c0f94..48ab00cc2f102f49d1f05d4555608fb19ab5469a 100644 (file)
@@ -95,6 +95,9 @@
     self->exDates = [[NSMutableArray alloc] initWithCapacity:4];
   [self->exDates addObject:_date];
 }
+- (BOOL)hasExceptionDates {
+  return [self->exDates count] > 0 ? YES : NO;
+}
 - (NSArray *)exceptionDates {
   return self->exDates;
 }