2014-01-10 20:12:53 +01:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2014, Inverse inc.
|
|
|
|
All rights reserved.
|
|
|
|
|
2014-01-13 17:46:32 +01:00
|
|
|
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 <COPYRIGHT HOLDER> 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.
|
2014-01-10 20:12:53 +01:00
|
|
|
|
|
|
|
*/
|
2014-01-13 17:46:32 +01:00
|
|
|
|
2014-01-10 20:12:53 +01:00
|
|
|
#import "iCalEvent+ActiveSync.h"
|
|
|
|
|
2014-01-13 22:25:14 +01:00
|
|
|
#import <Foundation/NSArray.h>
|
2014-01-10 22:48:39 +01:00
|
|
|
#import <Foundation/NSCalendarDate.h>
|
|
|
|
#import <Foundation/NSDate.h>
|
2014-01-10 20:12:53 +01:00
|
|
|
#import <Foundation/NSDictionary.h>
|
|
|
|
#import <Foundation/NSString.h>
|
2014-01-10 22:48:39 +01:00
|
|
|
#import <Foundation/NSTimeZone.h>
|
2014-01-10 20:12:53 +01:00
|
|
|
|
2014-01-27 17:30:43 +01:00
|
|
|
#import <NGExtensions/NSString+misc.h>
|
2014-02-17 16:01:44 +01:00
|
|
|
#import <NGObjWeb/WOContext.h>
|
|
|
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
2014-01-27 17:30:43 +01:00
|
|
|
|
2014-01-10 22:48:39 +01:00
|
|
|
#import <NGCards/iCalCalendar.h>
|
2014-01-10 20:12:53 +01:00
|
|
|
#import <NGCards/iCalDateTime.h>
|
2014-01-13 22:25:14 +01:00
|
|
|
#import <NGCards/iCalPerson.h>
|
2014-01-10 20:12:53 +01:00
|
|
|
|
2014-02-17 16:01:44 +01:00
|
|
|
#import <SOGo/SOGoUser.h>
|
|
|
|
#import <SOGo/SOGoUserDefaults.h>
|
|
|
|
|
2014-02-17 17:30:41 +01:00
|
|
|
#import <Appointments/iCalEntityObject+SOGo.h>
|
|
|
|
|
2014-03-28 19:44:00 +01:00
|
|
|
#include "iCalAlarm+ActiveSync.h"
|
2014-01-28 20:26:35 +01:00
|
|
|
#include "iCalRecurrenceRule+ActiveSync.h"
|
2014-01-10 20:12:53 +01:00
|
|
|
#include "iCalTimeZone+ActiveSync.h"
|
|
|
|
#include "NSDate+ActiveSync.h"
|
|
|
|
#include "NSString+ActiveSync.h"
|
|
|
|
|
|
|
|
@implementation iCalEvent (ActiveSync)
|
|
|
|
|
2014-02-17 17:30:41 +01:00
|
|
|
- (int) _attendeeStatus: (iCalPerson *) attendee
|
|
|
|
{
|
|
|
|
int attendee_status;
|
|
|
|
|
|
|
|
attendee_status = 5;
|
|
|
|
if ([[attendee partStat] caseInsensitiveCompare: @"ACCEPTED"] == NSOrderedSame)
|
|
|
|
attendee_status = 3;
|
|
|
|
else if ([[attendee partStat] caseInsensitiveCompare: @"DECLINED"] == NSOrderedSame)
|
|
|
|
attendee_status = 4;
|
|
|
|
else if ([[attendee partStat] caseInsensitiveCompare: @"TENTATIVE"] == NSOrderedSame)
|
|
|
|
attendee_status = 2;
|
|
|
|
|
|
|
|
return attendee_status;
|
|
|
|
}
|
|
|
|
|
2014-02-17 16:01:44 +01:00
|
|
|
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
2014-01-10 20:12:53 +01:00
|
|
|
{
|
|
|
|
NSMutableString *s;
|
2014-01-13 22:25:14 +01:00
|
|
|
NSArray *attendees;
|
|
|
|
|
|
|
|
iCalPerson *organizer, *attendee;
|
2014-01-10 20:12:53 +01:00
|
|
|
iCalTimeZone *tz;
|
2014-01-23 17:09:32 +01:00
|
|
|
id o;
|
|
|
|
|
|
|
|
int v;
|
2014-01-10 20:12:53 +01:00
|
|
|
|
2014-04-03 00:14:17 +02:00
|
|
|
NSTimeZone *userTimeZone;
|
|
|
|
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
|
|
|
|
2014-01-10 20:12:53 +01:00
|
|
|
s = [NSMutableString string];
|
|
|
|
|
2014-02-17 14:46:05 +01:00
|
|
|
[s appendFormat: @"<AllDayEvent xmlns=\"Calendar:\">%d</AllDayEvent>", ([self isAllDay] ? 1 : 0)];
|
|
|
|
|
2014-01-10 20:12:53 +01:00
|
|
|
// DTStamp -- http://msdn.microsoft.com/en-us/library/ee219470(v=exchg.80).aspx
|
|
|
|
if ([self timeStampAsDate])
|
2014-02-17 16:01:44 +01:00
|
|
|
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
2014-01-10 20:12:53 +01:00
|
|
|
else if ([self created])
|
2014-02-17 16:01:44 +01:00
|
|
|
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
2014-01-10 20:12:53 +01:00
|
|
|
|
|
|
|
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
|
|
|
|
if ([self startDate])
|
2014-04-03 00:14:17 +02:00
|
|
|
{
|
|
|
|
if ([self isAllDay])
|
|
|
|
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
|
|
|
|
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
|
|
|
|
hours: 0 minutes: 0
|
|
|
|
seconds: ([userTimeZone secondsFromGMTForDate: [self startDate]])*-1]
|
|
|
|
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
|
|
|
else
|
|
|
|
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
|
|
|
}
|
|
|
|
|
2014-01-10 20:12:53 +01:00
|
|
|
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
|
|
|
|
if ([self endDate])
|
2014-04-03 00:14:17 +02:00
|
|
|
{
|
|
|
|
if ([self isAllDay])
|
|
|
|
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
|
|
|
|
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
|
|
|
|
hours: 0 minutes: 0
|
|
|
|
seconds: ([userTimeZone secondsFromGMTForDate: [self endDate]])*-1]
|
|
|
|
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
|
|
|
else
|
|
|
|
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
|
|
|
}
|
|
|
|
|
2014-01-10 20:12:53 +01:00
|
|
|
// Timezone
|
|
|
|
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
|
|
|
|
|
|
|
|
if (!tz)
|
|
|
|
tz = [iCalTimeZone timeZoneForName: @"Europe/London"];
|
|
|
|
|
2014-02-17 16:01:44 +01:00
|
|
|
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
|
2014-01-23 17:09:32 +01:00
|
|
|
|
2014-02-17 14:46:05 +01:00
|
|
|
// Organizer and other invitations related properties
|
2014-01-13 22:25:14 +01:00
|
|
|
if ((organizer = [self organizer]))
|
|
|
|
{
|
2014-01-23 17:09:32 +01:00
|
|
|
o = [organizer rfc822Email];
|
|
|
|
if ([o length])
|
2014-02-17 14:46:05 +01:00
|
|
|
{
|
|
|
|
[s appendFormat: @"<Organizer_Email xmlns=\"Calendar:\">%@</Organizer_Email>", o];
|
|
|
|
|
|
|
|
o = [organizer cn];
|
|
|
|
if ([o length])
|
|
|
|
[s appendFormat: @"<Organizer_Name xmlns=\"Calendar:\">%@</Organizer_Name>", o];
|
|
|
|
}
|
2014-01-13 22:25:14 +01:00
|
|
|
}
|
|
|
|
|
2014-01-23 17:09:32 +01:00
|
|
|
// Attendees
|
2014-01-13 22:25:14 +01:00
|
|
|
attendees = [self attendees];
|
2014-01-10 20:12:53 +01:00
|
|
|
|
2014-01-13 22:25:14 +01:00
|
|
|
if ([attendees count])
|
|
|
|
{
|
2014-02-17 17:30:41 +01:00
|
|
|
int i, attendee_status, attendee_type;
|
2014-01-13 22:25:14 +01:00
|
|
|
|
|
|
|
[s appendString: @"<Attendees xmlns=\"Calendar:\">"];
|
|
|
|
|
|
|
|
for (i = 0; i < [attendees count]; i++)
|
|
|
|
{
|
|
|
|
[s appendString: @"<Attendee xmlns=\"Calendar:\">"];
|
|
|
|
|
|
|
|
attendee = [attendees objectAtIndex: i];
|
|
|
|
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [attendee rfc822Email]];
|
2014-04-10 12:59:18 +02:00
|
|
|
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
|
2014-01-23 17:09:32 +01:00
|
|
|
|
2014-02-17 17:30:41 +01:00
|
|
|
attendee_status = [self _attendeeStatus: attendee];
|
2014-01-13 22:25:14 +01:00
|
|
|
|
|
|
|
[s appendFormat: @"<Attendee_Status xmlns=\"Calendar:\">%d</Attendee_Status>", attendee_status];
|
|
|
|
|
|
|
|
// FIXME: handle resource
|
|
|
|
if ([[attendee role] caseInsensitiveCompare: @"REQ-PARTICIPANT"] == NSOrderedSame)
|
|
|
|
attendee_type = 1;
|
|
|
|
else
|
|
|
|
attendee_type = 2;
|
|
|
|
|
|
|
|
[s appendFormat: @"<Attendee_Type xmlns=\"Calendar:\">%d</Attendee_Type>", attendee_type];
|
|
|
|
[s appendString: @"</Attendee>"];
|
|
|
|
}
|
|
|
|
[s appendString: @"</Attendees>"];
|
|
|
|
}
|
2014-02-17 17:30:41 +01:00
|
|
|
|
|
|
|
// This depends on the 'NEEDS-ACTION' parameter.
|
|
|
|
// This will trigger the SendMail command
|
|
|
|
if ([self userIsAttendee: [context activeUser]])
|
|
|
|
{
|
|
|
|
iCalPerson *attendee;
|
|
|
|
|
|
|
|
int attendee_status;
|
|
|
|
|
|
|
|
attendee = [self userAsAttendee: [context activeUser]];
|
|
|
|
attendee_status = [self _attendeeStatus: attendee];
|
|
|
|
|
|
|
|
[s appendFormat: @"<ResponseRequested xmlns=\"Calendar:\">%d</ResponseRequested>", 1];
|
|
|
|
[s appendFormat: @"<ResponseType xmlns=\"Calendar:\">%d</ResponseType>", attendee_status];
|
|
|
|
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", 3];
|
|
|
|
[s appendFormat: @"<DisallowNewTimeProposal xmlns=\"Calendar:\">%d</DisallowNewTimeProposal>", 1];
|
|
|
|
|
|
|
|
// BusyStatus -- http://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
|
|
|
|
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", 2];
|
|
|
|
}
|
2014-01-13 22:25:14 +01:00
|
|
|
|
2014-01-10 20:12:53 +01:00
|
|
|
// Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx
|
|
|
|
if ([[self summary] length])
|
2014-02-17 16:01:44 +01:00
|
|
|
[s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
|
2014-01-10 20:12:53 +01:00
|
|
|
|
2014-01-23 17:09:32 +01:00
|
|
|
// Location
|
|
|
|
if ([[self location] length])
|
2014-02-17 16:01:44 +01:00
|
|
|
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentationInContext: context]];
|
2014-01-23 17:09:32 +01:00
|
|
|
|
|
|
|
// Importance - NOT SUPPORTED - DO NOT ENABLE
|
|
|
|
//o = [self priority];
|
|
|
|
//if ([o isEqualToString: @"9"])
|
|
|
|
// v = 0;
|
|
|
|
//else if ([o isEqualToString: @"1"])
|
|
|
|
// v = 2;
|
|
|
|
//else
|
|
|
|
// v = 1;
|
|
|
|
//[s appendFormat: @"<Importance xmlns=\"Calendar:\">%d</Importance>", v];
|
|
|
|
|
2014-01-10 20:12:53 +01:00
|
|
|
// UID -- http://msdn.microsoft.com/en-us/library/ee159919(v=exchg.80).aspx
|
|
|
|
if ([[self uid] length])
|
|
|
|
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [self uid]];
|
|
|
|
|
2014-01-23 17:09:32 +01:00
|
|
|
// Sensitivity
|
|
|
|
if ([[self accessClass] isEqualToString: @"PRIVATE"])
|
|
|
|
v = 2;
|
|
|
|
if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
|
|
|
|
v = 3;
|
|
|
|
else
|
|
|
|
v = 0;
|
|
|
|
|
|
|
|
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
|
2014-01-10 20:12:53 +01:00
|
|
|
|
|
|
|
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
|
2014-03-28 19:44:00 +01:00
|
|
|
// TODO: improve this to handle more alarm types
|
|
|
|
if ([self hasAlarms])
|
|
|
|
{
|
|
|
|
iCalAlarm *alarm;
|
|
|
|
|
|
|
|
alarm = [[self alarms] objectAtIndex: 0];
|
|
|
|
[s appendString: [alarm activeSyncRepresentationInContext: context]];
|
|
|
|
}
|
2014-01-23 17:09:32 +01:00
|
|
|
|
2014-01-28 20:26:35 +01:00
|
|
|
// Recurrence rules
|
|
|
|
if ([self isRecurrent])
|
|
|
|
{
|
2014-02-17 16:01:44 +01:00
|
|
|
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
|
2014-01-28 20:26:35 +01:00
|
|
|
}
|
|
|
|
|
2014-01-23 17:09:32 +01:00
|
|
|
// Comment
|
|
|
|
o = [self comment];
|
|
|
|
if ([o length])
|
|
|
|
{
|
2014-02-17 16:01:44 +01:00
|
|
|
o = [o activeSyncRepresentationInContext: context];
|
2014-01-23 17:09:32 +01:00
|
|
|
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
|
|
|
[s appendFormat: @"<Type>%d</Type>", 1];
|
|
|
|
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
|
|
|
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
|
|
|
|
[s appendFormat: @"<Data>%@</Data>", o];
|
|
|
|
[s appendString: @"</Body>"];
|
|
|
|
}
|
|
|
|
|
|
|
|
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
|
2014-01-10 20:12:53 +01:00
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2014-01-13 22:25:14 +01:00
|
|
|
// To understand meeting requests/responses, see:
|
2014-01-10 20:12:53 +01:00
|
|
|
//
|
2014-01-13 22:25:14 +01:00
|
|
|
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/22/working-with-meeting-requests-in-exchange-activesync.aspx
|
|
|
|
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/29/working-with-meeting-responses-in-exchange-activesync.aspx
|
2014-01-10 20:12:53 +01:00
|
|
|
//
|
2014-02-03 16:24:33 +01:00
|
|
|
//
|
|
|
|
// Here is an example of a Sync call when sogo10 accepts an invitation from sogo3:
|
|
|
|
//
|
|
|
|
// <Change>
|
|
|
|
// <ServerId>2978-52EA9D00-1-A253E70.ics</ServerId>
|
|
|
|
// <ApplicationData>
|
|
|
|
// <TimeZone xmlns="Calendar:">LAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==</TimeZone>
|
|
|
|
// <AllDayEvent xmlns="Calendar:">0</AllDayEvent>
|
|
|
|
// <StartTime xmlns="Calendar:">20140207T130000Z</StartTime>
|
|
|
|
// <EndTime xmlns="Calendar:">20140207T140000Z</EndTime>
|
|
|
|
// <DTStamp xmlns="Calendar:">20140130T185245Z</DTStamp>
|
|
|
|
// <Subject xmlns="Calendar:">test 8</Subject>
|
|
|
|
// <Sensitivity xmlns="Calendar:">0</Sensitivity>
|
|
|
|
// <Body xmlns="AirSyncBase:">
|
|
|
|
// <Type>1</Type>
|
|
|
|
// <Data/>
|
|
|
|
// </Body>
|
|
|
|
// <Organizer_Email xmlns="Calendar:">sogo3@example.com</Organizer_Email>
|
|
|
|
// <UID xmlns="Calendar:">2978-52EA9D00-1-A253E70</UID>
|
|
|
|
// <Attendees xmlns="Calendar:">
|
|
|
|
// <Attendee>
|
|
|
|
// <Attendee_Name>sogo10</Attendee_Name>
|
|
|
|
// <Attendee_Email>sogo10@example.com</Attendee_Email>
|
|
|
|
// <Attendee_Type>1</Attendee_Type>
|
|
|
|
// </Attendee>
|
|
|
|
// </Attendees>
|
|
|
|
// <BusyStatus xmlns="Calendar:">2</BusyStatus>
|
|
|
|
// <MeetingStatus xmlns="Calendar:">3</MeetingStatus>
|
|
|
|
// <Organizer_Name xmlns="Calendar:">Wolfgang Fritz</Organizer_Name>
|
|
|
|
// </ApplicationData>
|
|
|
|
// </Change>
|
|
|
|
//
|
2014-01-10 20:12:53 +01:00
|
|
|
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
2014-02-17 16:01:44 +01:00
|
|
|
inContext: (WOContext *) context
|
2014-01-10 20:12:53 +01:00
|
|
|
{
|
2014-01-10 22:48:39 +01:00
|
|
|
iCalDateTime *start, *end;
|
|
|
|
NSTimeZone *userTimeZone;
|
|
|
|
iCalTimeZone *tz;
|
2014-01-10 20:12:53 +01:00
|
|
|
id o;
|
2014-01-10 22:48:39 +01:00
|
|
|
|
|
|
|
NSInteger tzOffset;
|
|
|
|
BOOL isAllDay;
|
2014-01-10 20:12:53 +01:00
|
|
|
|
|
|
|
if ((o = [theValues objectForKey: @"UID"]))
|
|
|
|
[self setUid: o];
|
|
|
|
|
2014-01-12 01:31:39 +01:00
|
|
|
// FIXME: merge with iCalToDo
|
2014-01-10 20:12:53 +01:00
|
|
|
if ((o = [theValues objectForKey: @"Subject"]))
|
|
|
|
[self setSummary: o];
|
|
|
|
|
2014-01-10 22:48:39 +01:00
|
|
|
isAllDay = NO;
|
2014-01-10 20:12:53 +01:00
|
|
|
if ([[theValues objectForKey: @"AllDayEvent"] intValue])
|
|
|
|
{
|
2014-01-10 22:48:39 +01:00
|
|
|
isAllDay = YES;
|
|
|
|
}
|
2014-01-10 20:12:53 +01:00
|
|
|
|
2014-01-10 22:48:39 +01:00
|
|
|
//
|
|
|
|
// 0- free, 1- tentative, 2- busy and 3- out of office
|
|
|
|
//
|
|
|
|
if ((o = [theValues objectForKey: @"BusyStatus"]))
|
|
|
|
{
|
|
|
|
[o intValue];
|
2014-01-10 20:12:53 +01:00
|
|
|
}
|
|
|
|
|
2014-01-10 22:48:39 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
if ((o = [theValues objectForKey: @"MeetingStatus"]))
|
|
|
|
{
|
|
|
|
[o intValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// 0- normal, 1- personal, 2- private and 3-confidential
|
|
|
|
//
|
|
|
|
if ((o = [theValues objectForKey: @"Sensitivy"]))
|
|
|
|
{
|
|
|
|
switch ([o intValue])
|
|
|
|
{
|
|
|
|
case 2:
|
|
|
|
[self setAccessClass: @"PRIVATE"];
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
[self setAccessClass: @"CONFIDENTIAL"];
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
default:
|
|
|
|
[self setAccessClass: @"PUBLIC"];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((o = [theValues objectForKey: @"TimeZone"]))
|
|
|
|
{
|
|
|
|
// Ugh, we ignore it for now.
|
2014-02-17 16:01:44 +01:00
|
|
|
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
2014-01-10 22:48:39 +01:00
|
|
|
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
|
|
|
[(iCalCalendar *) parent addTimeZone: tz];
|
|
|
|
}
|
|
|
|
|
2014-01-12 01:31:39 +01:00
|
|
|
// FIXME: merge with iCalToDo
|
2014-01-10 20:12:53 +01:00
|
|
|
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
|
|
|
[self setComment: o];
|
|
|
|
|
|
|
|
if ((o = [theValues objectForKey: @"Location"]))
|
|
|
|
[self setLocation: o];
|
|
|
|
|
|
|
|
if ((o = [theValues objectForKey: @"StartTime"]))
|
2014-01-10 22:48:39 +01:00
|
|
|
{
|
|
|
|
o = [o calendarDate];
|
|
|
|
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
|
|
|
[start setTimeZone: tz];
|
|
|
|
|
|
|
|
if (isAllDay)
|
|
|
|
{
|
2014-04-03 00:14:17 +02:00
|
|
|
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
|
|
|
o = [o dateByAddingYears: 0 months: 0 days: 0
|
|
|
|
hours: 0 minutes: 0
|
|
|
|
seconds: tzOffset];
|
2014-01-10 22:48:39 +01:00
|
|
|
[start setDate: o];
|
|
|
|
[start setTimeZone: nil];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
|
|
|
o = [o dateByAddingYears: 0 months: 0 days: 0
|
|
|
|
hours: 0 minutes: 0
|
|
|
|
seconds: tzOffset];
|
|
|
|
[start setDateTime: o];
|
|
|
|
}
|
|
|
|
}
|
2014-01-10 20:12:53 +01:00
|
|
|
|
|
|
|
if ((o = [theValues objectForKey: @"EndTime"]))
|
2014-01-10 22:48:39 +01:00
|
|
|
{
|
|
|
|
o = [o calendarDate];
|
|
|
|
end = (iCalDateTime *) [self uniqueChildWithTag: @"dtend"];
|
|
|
|
[end setTimeZone: tz];
|
|
|
|
|
|
|
|
if (isAllDay)
|
|
|
|
{
|
2014-04-03 00:14:17 +02:00
|
|
|
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
|
|
|
o = [o dateByAddingYears: 0 months: 0 days: 0
|
|
|
|
hours: 0 minutes: 0
|
|
|
|
seconds: tzOffset];
|
2014-01-10 22:48:39 +01:00
|
|
|
[end setDate: o];
|
|
|
|
[end setTimeZone: nil];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
|
|
|
o = [o dateByAddingYears: 0 months: 0 days: 0
|
|
|
|
hours: 0 minutes: 0
|
|
|
|
seconds: tzOffset];
|
|
|
|
[end setDateTime: o];
|
|
|
|
}
|
|
|
|
}
|
2014-01-28 20:26:35 +01:00
|
|
|
|
2014-03-28 19:44:00 +01:00
|
|
|
//
|
|
|
|
// 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];
|
|
|
|
}
|
|
|
|
|
2014-01-28 20:26:35 +01:00
|
|
|
// Recurrence
|
|
|
|
if ((o = [theValues objectForKey: @"Recurrence"]))
|
|
|
|
{
|
|
|
|
iCalRecurrenceRule *rule;
|
|
|
|
|
|
|
|
rule = [[iCalRecurrenceRule alloc] init];
|
|
|
|
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
|
|
|
|
RELEASE(rule);
|
|
|
|
|
2014-02-17 16:01:44 +01:00
|
|
|
[rule takeActiveSyncValues: o inContext: context];
|
2014-01-28 20:26:35 +01:00
|
|
|
}
|
2014-02-03 16:24:33 +01:00
|
|
|
|
2014-02-17 17:30:41 +01:00
|
|
|
// Organizer - we don't touch the value unless we're the organizer
|
2014-02-17 21:49:22 +01:00
|
|
|
if ((o = [theValues objectForKey: @"Organizer_Email"]) &&
|
|
|
|
([self userIsOrganizer: [context activeUser]] || [[context activeUser] hasEmail: o]))
|
2014-02-03 16:24:33 +01:00
|
|
|
{
|
2014-02-17 21:49:22 +01:00
|
|
|
iCalPerson *person;
|
|
|
|
|
|
|
|
person = [iCalPerson elementWithTag: @"organizer"];
|
|
|
|
[person setEmail: o];
|
|
|
|
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
|
|
|
|
[person setPartStat: @"ACCEPTED"];
|
|
|
|
[self setOrganizer: person];
|
2014-02-03 16:24:33 +01:00
|
|
|
}
|
|
|
|
|
2014-02-17 17:30:41 +01:00
|
|
|
// Attendees - we don't touch the values if we're an attendee. This is gonna
|
|
|
|
// be done automatically by the ActiveSync client when invoking MeetingResponse.
|
2014-02-17 21:49:22 +01:00
|
|
|
if (![self userIsAttendee: [context activeUser]])
|
2014-02-03 16:24:33 +01:00
|
|
|
{
|
2014-02-17 17:30:41 +01:00
|
|
|
if ((o = [theValues objectForKey: @"Attendees"]))
|
2014-02-03 16:24:33 +01:00
|
|
|
{
|
2014-02-17 17:30:41 +01:00
|
|
|
NSMutableArray *attendees;
|
|
|
|
NSDictionary *attendee;
|
|
|
|
iCalPerson *person;
|
|
|
|
int status, i;
|
2014-02-03 16:24:33 +01:00
|
|
|
|
2014-02-17 17:30:41 +01:00
|
|
|
attendees = [NSMutableArray array];
|
|
|
|
|
|
|
|
for (i = 0; i < [o count]; i++)
|
2014-02-03 16:24:33 +01:00
|
|
|
{
|
2014-02-17 17:30:41 +01:00
|
|
|
// Each attendee has is a dictionary similar to this:
|
|
|
|
// { "Attendee_Email" = "sogo3@example.com"; "Attendee_Name" = "Wolfgang Fritz"; "Attendee_Status" = 5; "Attendee_Type" = 1; }
|
|
|
|
attendee = [o objectAtIndex: i];
|
|
|
|
|
|
|
|
person = [iCalPerson elementWithTag: @"attendee"];
|
|
|
|
[person setCn: [attendee objectForKey: @"Attendee_Name"]];
|
|
|
|
[person setEmail: [attendee objectForKey: @"Attendee_Email"]];
|
|
|
|
|
|
|
|
status = [[attendee objectForKey: @"Attendee_Status"] intValue];
|
|
|
|
|
|
|
|
switch (status)
|
|
|
|
{
|
|
|
|
case 2:
|
|
|
|
[person setPartStat: @"TENTATIVE"];
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
[person setPartStat: @"ACCEPTED"];
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
[person setPartStat: @"DECLINED"];
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
case 5:
|
|
|
|
default:
|
|
|
|
[person setPartStat: @"NEEDS-ACTION"];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: handle Attendee_Type
|
|
|
|
|
|
|
|
[attendees addObject: person];
|
2014-02-03 16:24:33 +01:00
|
|
|
}
|
|
|
|
|
2014-02-17 17:30:41 +01:00
|
|
|
[self setAttendees: attendees];
|
2014-02-03 16:24:33 +01:00
|
|
|
}
|
|
|
|
}
|
2014-01-10 20:12:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|