From b14e99b32a609063d484eb2472684831e4faa214 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Mon, 10 Feb 2014 20:16:43 -0500 Subject: [PATCH] New prefs for intervals, fixed missing events in meeting requests, bumped v14.1 --- ActiveSync/SOGoActiveSyncDispatcher+Sync.m | 63 ++++++++++++++------- ActiveSync/SOGoActiveSyncDispatcher.m | 64 +++++++++++++--------- SoObjects/SOGo/SOGoSystemDefaults.h | 9 +-- SoObjects/SOGo/SOGoSystemDefaults.m | 41 ++++++++++++-- 4 files changed, 124 insertions(+), 53 deletions(-) diff --git a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m index a2f2b3a44..1fe766088 100644 --- a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m +++ b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m @@ -73,6 +73,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import #import #import +#import #import #import @@ -155,15 +156,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NSArray *additions; id anAddition, sogoObject, o; + BOOL is_new; int i; additions = (id)[theDocumentElement getElementsByTagName: @"Add"]; - if ([additions count]) { for (i = 0; i < [additions count]; i++) { anAddition = [additions objectAtIndex: i]; + is_new = YES; clientId = [[(id)[anAddition getElementsByTagName: @"ClientId"] lastObject] textValue]; allValues = [NSMutableDictionary dictionaryWithDictionary: [[(id)[anAddition getElementsByTagName: @"ApplicationData"] lastObject] applicationData]]; @@ -180,11 +182,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. break; case ActiveSyncEventFolder: { - serverId = [NSString stringWithFormat: @"%@.ics", [theCollection globallyUniqueObjectId]]; - sogoObject = [[SOGoAppointmentObject alloc] initWithName: serverId - inContainer: theCollection]; + // Before adding a new appointment, we check if one is already present with the same UID. If that's + // the case, let's just update it. This can happen if for example, an iOS based device receives the + // invitation email and choses "Add to calendar" BEFORE actually syncing the calendar. That would + // create a duplicate on the server. + if ([allValues objectForKey: @"UID"]) + serverId = [NSString stringWithFormat: @"%@.ics", [allValues objectForKey: @"UID"]]; + else + serverId = [NSString stringWithFormat: @"%@.ics", [theCollection globallyUniqueObjectId]]; + [allValues setObject: [[[context activeUser] userDefaults] timeZone] forKey: @"SOGoUserTimeZone"]; - o = [sogoObject component: YES secure: NO]; + + sogoObject = [theCollection lookupName: serverId + inContext: context + acquire: NO]; + + // If object isn't found, we 'create' a new one + if ([sogoObject isKindOfClass: [NSException class]]) + { + sogoObject = [[SOGoAppointmentObject alloc] initWithName: serverId + inContainer: theCollection]; + o = [sogoObject component: YES secure: NO]; + } + else + { + o = [sogoObject component: NO secure: NO]; + is_new = NO; + } } break; case ActiveSyncTaskFolder: @@ -205,7 +229,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } [o takeActiveSyncValues: allValues]; - [sogoObject setIsNew: YES]; + [sogoObject setIsNew: is_new]; [sogoObject saveComponent: o]; // Everything is fine, lets generate our response @@ -845,12 +869,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - (void) processSync: (id ) theDocumentElement inResponse: (WOResponse *) theResponse { + SOGoSystemDefaults *defaults; id aCollection; - NSArray *allCollections; NSMutableString *output, *s; + NSArray *allCollections; NSData *d; - int i, j, heartbeatInterval; + int i, j, defaultInterval, heartbeatInterval, internalInterval; BOOL changeDetected; // We initialize our output buffer @@ -859,21 +884,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [output appendString: @""]; [output appendString: @""]; [output appendString: @""]; - + + defaults = [SOGoSystemDefaults sharedSystemDefaults]; heartbeatInterval = [[[(id)[theDocumentElement getElementsByTagName: @"HeartbeatInterval"] lastObject] textValue] intValue]; + defaultInterval = [defaults maximumSyncInterval]; + internalInterval = [defaults internalSyncInterval]; // We check to see if our heartbeat interval falls into the supported ranges. - if (heartbeatInterval > 300 || heartbeatInterval < 1) + if (heartbeatInterval > defaultInterval || heartbeatInterval < 1) { // Interval is too long, inform the client. - heartbeatInterval = 300; + heartbeatInterval = defaultInterval; - //[output appendFormat: @"%d", 300]; + // Outlook doesn't like this... + //[output appendFormat: @"%d", defaultInterval]; //[output appendFormat: @"%d", 14]; - //[output appendString: @""]; - //d = [[output dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml]; - //[theResponse setContent: d]; - //return; } [output appendString: @""]; @@ -881,7 +906,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. allCollections = (id)[theDocumentElement getElementsByTagName: @"Collection"]; // We enter our loop detection change - for (i = 0; i < (heartbeatInterval/60); i++) + for (i = 0; i < (defaultInterval/internalInterval); i++) { s = [NSMutableString string]; @@ -900,8 +925,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } else { - NSLog(@"Sleeping 60 seconds while detecting changes..."); - sleep(60); + NSLog(@"Sleeping %d seconds while detecting changes...", internalInterval); + sleep(internalInterval); } } diff --git a/ActiveSync/SOGoActiveSyncDispatcher.m b/ActiveSync/SOGoActiveSyncDispatcher.m index 60082b451..0b4e7bfa2 100644 --- a/ActiveSync/SOGoActiveSyncDispatcher.m +++ b/ActiveSync/SOGoActiveSyncDispatcher.m @@ -79,6 +79,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import #import #import +#import #import #import #import @@ -735,6 +736,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. inResponse: (WOResponse *) theResponse { NSString *realCollectionId, *requestId, *participationStatus; + SOGoMailObject *mailObject; NSMutableString *s; NSData *d; @@ -758,8 +760,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // We fetch the calendar information based on the email (requestId) in the user's INBOX (or elsewhere) // // FIXME: that won't work too well for external invitations... - SOGoMailObject *mailObject; - mailObject = [collection lookupName: requestId inContext: context acquire: 0]; @@ -785,22 +785,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. else participationStatus = @"DECLINED"; - [appointmentObject changeParticipationStatus: participationStatus - withDelegate: nil]; - - [s appendString: @""]; - [s appendString: @""]; - [s appendString: @""]; - [s appendString: @""]; - [s appendFormat: @"%@", requestId]; - [s appendFormat: @"%@", [event uid]]; - [s appendFormat: @"%d", status]; - [s appendString: @""]; - [s appendString: @""]; - - d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml]; - - [theResponse setContent: d]; + if (![appointmentObject isKindOfClass: [NSException class]]) + { + [appointmentObject changeParticipationStatus: participationStatus + withDelegate: nil]; + + [s appendString: @""]; + [s appendString: @""]; + [s appendString: @""]; + [s appendString: @""]; + [s appendFormat: @"%@", requestId]; + [s appendFormat: @"%@", [event uid]]; + [s appendFormat: @"%d", status]; + [s appendString: @""]; + [s appendString: @""]; + + d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml]; + + [theResponse setContent: d]; + } + else + { + [theResponse setStatus: 500]; + } } else { @@ -919,28 +926,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - (void) processPing: (id ) theDocumentElement inResponse: (WOResponse *) theResponse { + SOGoSystemDefaults *defaults; NSMutableString *s; NSData *d; - int heartbeatInterval, status; + int heartbeatInterval, defaultInterval, status; + + defaults = [SOGoSystemDefaults sharedSystemDefaults]; + defaultInterval = [defaults maximumPingInterval]; if (theDocumentElement) heartbeatInterval = [[[(id)[theDocumentElement getElementsByTagName: @"HeartbeatInterval"] lastObject] textValue] intValue]; else - heartbeatInterval = 60; + heartbeatInterval = defaultInterval; - if (heartbeatInterval > 60 || heartbeatInterval == 0) + if (heartbeatInterval > defaultInterval || heartbeatInterval == 0) { - heartbeatInterval = 60; + heartbeatInterval = defaultInterval; status = 5; } else { - NSLog(@"Got Ping request with valid interval - sleeping for 60 seconds."); - sleep(60); status = 1; } + NSLog(@"Got Ping request with valid interval - sleeping for %d seconds.", heartbeatInterval); + sleep(heartbeatInterval); + // We generate our response s = [NSMutableString string]; [s appendString: @""]; @@ -1513,9 +1525,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [self performSelector: aSelector withObject: documentElement withObject: theResponse]; [theResponse setHeader: @"application/vnd.ms-sync.wbxml" forKey: @"Content-Type"]; - [theResponse setHeader: @"14.0" forKey: @"MS-Server-ActiveSync"]; + [theResponse setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"]; [theResponse setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,Provision,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"]; - [theResponse setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0" forKey: @"MS-ASProtocolVersions"]; + [theResponse setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"]; RELEASE(context); diff --git a/SoObjects/SOGo/SOGoSystemDefaults.h b/SoObjects/SOGo/SOGoSystemDefaults.h index cb705f560..3678516ff 100644 --- a/SoObjects/SOGo/SOGoSystemDefaults.h +++ b/SoObjects/SOGo/SOGoSystemDefaults.h @@ -1,9 +1,6 @@ /* SOGoSystemDefaults.h - this file is part of SOGo * - * Copyright (C) 2009-2013 Inverse inc. - * - * Author: Wolfgang Sourdeau - * Francis Lachapelle + * Copyright (C) 2009-2014 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,6 +92,10 @@ - (int) maximumSubmissionInterval; - (int) messageSubmissionBlockInterval; +- (int) maximumPingInterval; +- (int) maximumSyncInterval; +- (int) internalSyncInterval; + @end #endif /* SOGOSYSTEMDEFAULTS_H */ diff --git a/SoObjects/SOGo/SOGoSystemDefaults.m b/SoObjects/SOGo/SOGoSystemDefaults.m index 0457fae4b..52a35f868 100644 --- a/SoObjects/SOGo/SOGoSystemDefaults.m +++ b/SoObjects/SOGo/SOGoSystemDefaults.m @@ -1,11 +1,8 @@ /* SOGoSystemDefaults.m - this file is part of SOGo * - * Copyright (C) 2009-2013 Inverse inc. + * Copyright (C) 2009-2014 Inverse inc. * Copyright (C) 2012 Jeroen Dekkers * - * Author: Wolfgang Sourdeau - * Francis Lachapelle - * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -582,4 +579,40 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict, return v; } +- (int) maximumPingInterval +{ + int v; + + v = [self integerForKey: @"SOGoMaximumPingInterval"]; + + if (!v) + v = 5; + + return v; +} + +- (int) maximumSyncInterval +{ + int v; + + v = [self integerForKey: @"SOGoMaximumSyncInterval"]; + + if (!v) + v = 30; + + return v; +} + +- (int) internalSyncInterval +{ + int v; + + v = [self integerForKey: @"SOGoInternalSyncInterval"]; + + if (!v) + v = 10; + + return v; +} + @end