diff --git a/ActiveSync/GNUmakefile b/ActiveSync/GNUmakefile index 12f12e56b..969580670 100644 --- a/ActiveSync/GNUmakefile +++ b/ActiveSync/GNUmakefile @@ -9,6 +9,7 @@ ActiveSync_PRINCIPAL_CLASS = ActiveSyncProduct ActiveSync_OBJC_FILES = \ ActiveSyncProduct.m \ + iCalAlarm+ActiveSync.m \ iCalEvent+ActiveSync.m \ iCalRecurrenceRule+ActiveSync.m \ iCalTimeZone+ActiveSync.m \ @@ -30,7 +31,7 @@ ActiveSync_RESOURCE_FILES += \ ADDITIONAL_OBJCFLAGS += -Wno-deprecated-declarations ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/ -ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/ +ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/ ADDITIONAL_INCLUDE_DIRS += -I/usr/include/libwbxml-1.0/ ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -lwbxml2 diff --git a/ActiveSync/iCalAlarm+ActiveSync.h b/ActiveSync/iCalAlarm+ActiveSync.h new file mode 100644 index 000000000..838c5042c --- /dev/null +++ b/ActiveSync/iCalAlarm+ActiveSync.h @@ -0,0 +1,46 @@ +/* + +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. + +*/ +#ifndef __ICALALARMACTIVESYNC_H__ +#define __ICALALARMACTIVESYNC_H__ + +#import + +@class NSString; +@class WOContext; + +@interface iCalAlarm (ActiveSync) + +- (NSString *) activeSyncRepresentationInContext: (WOContext *) context; +- (void) takeActiveSyncValues: (NSDictionary *) theValues + inContext: (WOContext *) context; + +@end + +#endif diff --git a/ActiveSync/iCalAlarm+ActiveSync.m b/ActiveSync/iCalAlarm+ActiveSync.m new file mode 100644 index 000000000..33e6dbb73 --- /dev/null +++ b/ActiveSync/iCalAlarm+ActiveSync.m @@ -0,0 +1,106 @@ +/* + +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 "iCalAlarm+ActiveSync.h" + +#import +#import + +#import +#import +#import + +#import +#import +#import + +@implementation iCalAlarm (ActiveSync) + +- (NSString *) activeSyncRepresentationInContext: (WOContext *) context +{ + NSMutableString *s; + + s = [NSMutableString string]; + + if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame) + { + NSCalendarDate *nextAlarmDate; + NSInteger delta; + + nextAlarmDate = [self nextAlarmDate]; + delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60); + + // don't send negative reminder - not supported + if (delta > 0) + [s appendFormat: @"%d", delta]; + } + + return s; +} + +- (void) takeActiveSyncValues: (NSDictionary *) theValues + inContext: (WOContext *) context +{ + iCalTrigger *trigger; + id o; + + o = [theValues objectForKey: @"Reminder"]; + + // Outlook: if reminder is set to 0 minutes before start save it as 1 minute since -> 0 minutes in not accepted by SOGo + if ([o isEqualToString: @"0"]) + o = @"1"; + + trigger = [iCalTrigger elementWithTag: @"TRIGGER"]; + [trigger setValueType: @"DURATION"]; + [self setTrigger: trigger]; + [self setAction: @"DISPLAY"]; + + // SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days) + // 1week = -P1W + // 2weeks > -PxD + // xdays > -PxD + // xhours -> -PTxH + // xmin -> -PTxM + if ([o intValue] == 10080) + [trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""]; + else + { + if (([o intValue] % 1440) == 0) + [trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""]; + else + { + if (([o intValue] % 60) == 0) + [trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""]; + else + [trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""]; + } + } +} + +@end diff --git a/ActiveSync/iCalEvent+ActiveSync.m b/ActiveSync/iCalEvent+ActiveSync.m index 05f18a3ce..a6b4c80f0 100644 --- a/ActiveSync/iCalEvent+ActiveSync.m +++ b/ActiveSync/iCalEvent+ActiveSync.m @@ -50,6 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import +#include "iCalAlarm+ActiveSync.h" #include "iCalRecurrenceRule+ActiveSync.h" #include "iCalTimeZone+ActiveSync.h" #include "NSDate+ActiveSync.h" @@ -209,7 +210,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [s appendFormat: @"%d", v]; // Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx - // TODO + // TODO: improve this to handle more alarm types + if ([self hasAlarms]) + { + iCalAlarm *alarm; + + alarm = [[self alarms] objectAtIndex: 0]; + [s appendString: [alarm activeSyncRepresentationInContext: context]]; + } // Recurrence rules if ([self isRecurrent]) @@ -390,6 +398,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } } + // + // If an alarm is deinfed with an action != DISPLAY, we ignore the alarm - don't want to overwrite. + // + if ([self hasAlarms] && [[[[self alarms] objectAtIndex: 0] action] caseInsensitiveCompare: @"DISPLAY"] != NSOrderedSame) + { + // Ignore the alarm for now + } + else if ((o = [theValues objectForKey: @"Reminder"])) + { + // NOTE: Outlook sends a 15 min reminder (18 hour for allday) if no reminder is specified + // although no default reminder is defined (File -> Options -> Clendar -> Calendar Options - > Default Reminders) + // + // http://answers.microsoft.com/en-us/office/forum/office_2013_release-outlook/desktop-outlook-calendar-creates-entries-with/9aef72d8-81bb-4a32-a6ab-bf7d216fb811?page=5&tm=1395690285088 + // + iCalAlarm *alarm; + + alarm = [[iCalAlarm alloc] init]; + [alarm takeActiveSyncValues: theValues inContext: context]; + + [self removeAllAlarms]; + [self addToAlarms: alarm]; + RELEASE(alarm); + } + else + { + // We remove existing alarm since no reminder in the ActiveSync payload + [self removeAllAlarms]; + } + // Recurrence if ((o = [theValues objectForKey: @"Recurrence"])) { diff --git a/NEWS b/NEWS index ffcbfa69e..9dc0f70a9 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ 2.2.3 (2014-MM-DD) ------------------ +Enhancements + - initial support for ActiveSync event reminders support (#2681) + Bug fixes - fixed possible exception when retrieving the default event reminder value on 64bit architectures (#2678) - fixed calling unescapeHTML on null variables to avoid JavaScript exceptions in Contacts module