/* Copyright (c) 2014, Inverse inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Inverse inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "iCalRecurrenceRule+ActiveSync.h" #import #import #import #import #import #import #import #import #import "NSCalendarDate+ActiveSync.h" #import "NSDate+ActiveSync.h" @implementation iCalRecurrenceRule (ActiveSync) - (NSCalendarDate *) _adjustedStartDate { iCalTimeZone *timeZone; timeZone = [(iCalDateTime *)[[self parent] firstChildWithTag: @"dtstart"] timeZone]; if (timeZone) return [timeZone computedDateForDate: [[self parent] startDate]]; else return [[self parent] startDate]; } - (NSString *) activeSyncRepresentationInContext: (WOContext *) context { NSMutableString *s; NSString *t; int type; s = [NSMutableString string]; if ([[self parent] isKindOfClass: [iCalToDo class]]) t = @"Tasks"; else t = @"Calendar"; [s appendFormat: @"", t]; // 0 -> daily, 1 -> weekly, 2 -> montly, 5 -> yearly type = 0; if ([self frequency] == iCalRecurrenceFrequenceDaily) { type = 0; // 1 -> sunday, 2 -> monday, 4 -> tuesday, 8 -> wednesday, 16 -> thursday, 32 -> friday, 64 -> saturday, 127 -> last day of month (montly or yearl recurrences only) if ([[self byDayMask] isWeekDays]) { [s appendFormat: @"%d", t, (2|4|8|16|32)]; } else { [s appendFormat: @"%d", t, [self repeatInterval]]; } } else if ([self frequency] == iCalRecurrenceFrequenceWeekly) { iCalWeekOccurrences *occurrences; int i, v; type = 1; occurrences = [[self byDayMask] weekDayOccurrences]; v = 0; if (occurrences) { for (i = 0; i < 7; i++) { if (occurrences[0][i]) v += (1 << i); } } else { // No byDayMask, we take the event's start date to compute the DayOfWeek // 0 == Sunday, 6 == Saturday v = (1 << [[self _adjustedStartDate] dayOfWeek]); } [s appendFormat: @"%d", t, v]; [s appendFormat: @"%d", t, [self repeatInterval]]; } else if ([self frequency] == iCalRecurrenceFrequenceMonthly) { if ([[self byDay] length]) { int firstOccurrence; iCalByDayMask *dm; type = 3; // recurs monthly on the nth day dm = [self byDayMask]; firstOccurrence = [dayMask firstOccurrence]; // Handle the case for "Last day of the month" if (firstOccurrence < 0) firstOccurrence = 5; [s appendFormat: @"%d", t, (1 << [dm firstDay])]; [s appendFormat: @"%d", t, firstOccurrence]; [s appendFormat: @"%d", t, [self repeatInterval]]; } else if ([[self byMonthDay] count]) { NSArray *days; type = 2; // recurs monthly days = [self byMonthDay]; if ([days count] > 0 && [[days objectAtIndex: 0] intValue] < 0) { // Last day of the month iCalByDayMask *dm; dm = [self byDayMask]; [s appendFormat: @"%d", t, (1 << [dm firstDay])]; [s appendFormat: @"%d", t, 5]; [s appendFormat: @"%d", t, [self repeatInterval]]; } else { // Unsupported rule in ActiveSync/Outlook. Rule that says "Repeat on the 7th and 8th of each month". // FIXME } } else { // Simple reccurrence rule of type "Monthly" type = 2; [s appendFormat: @"%d", t, [[self _adjustedStartDate] dayOfMonth]]; } } else if ([self frequency] == iCalRecurrenceFrequenceYearly) { type = 6; // Yearly on the nth day if ([[self flattenedValuesForKey: @"bymonth"] length]) { if ([[self byDay] length]) { int firstOccurrence; iCalByDayMask *dm; dm = [self byDayMask]; firstOccurrence = [dm firstOccurrence]; if (firstOccurrence < 0) firstOccurrence = 5; [s appendFormat: @"%d", t, (1 << [dm firstDay])]; [s appendFormat: @"%d", t, firstOccurrence]; [s appendFormat: @"%@", t, [self flattenedValuesForKey: @"bymonth"]]; } else { type = 5; // Yearly [s appendFormat: @"%@", t, [self flattenedValuesForKey: @"bymonthday"]]; [s appendFormat: @"%@", t, [self flattenedValuesForKey: @"bymonth"]]; } } else { type = 5; [s appendFormat: @"%d", t, [[self _adjustedStartDate] dayOfMonth]]; [s appendFormat: @"%d", t, [[self _adjustedStartDate] monthOfYear]]; } } [s appendFormat: @"%d", t, type]; if ([[self parent] isKindOfClass: [iCalToDo class]]) [s appendFormat: @"%@", t, [[[self parent] startDate] activeSyncRepresentationInContext: context]]; // Occurrences / Until if ([self repeatCount]) { [s appendFormat: @"%@", t, [self flattenedValuesForKey: @"count"]]; } else if ([self untilDate]) { NSCalendarDate *date; date = [self untilDate]; //ud = [[context activeUser] userDefaults]; //[date setTimeZone: [ud timeZone]]; [s appendFormat: @"%@", t, [date activeSyncRepresentationWithoutSeparatorsInContext: context]]; } [s appendString: @""]; return s; } // // // - (void) _setByDayFromValues: (NSDictionary *) theValues { NSString *day; id o; unsigned int day_of_week; int i, week_of_month; o = [theValues objectForKey: @"Recurrence_DayOfWeek"]; // The documentation says WeekOfMonth must be between 1 and 5. The value // 5 means "last week of month" week_of_month = [[theValues objectForKey: @"Recurrence_WeekOfMonth"] intValue]; if (week_of_month > 4) week_of_month = -1; // We find the correct day of the week day_of_week = [o intValue]; for (i = 0; i < 7; i++) { if ((1<