mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-03-24 23:52:43 +00:00
Merge to 2.2.13
This commit is contained in:
@@ -193,11 +193,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if ((o = [self note]))
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
[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>"];
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <Foundation/NSCalendarDate.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSTimeZone.h>
|
||||
|
||||
#include <SOGo/NSString+Utilities.h>
|
||||
#include <SOGo/NSData+Crypto.h>
|
||||
@@ -127,13 +128,17 @@ static NSArray *easCommandParameters = nil;
|
||||
//
|
||||
- (NSCalendarDate *) calendarDate
|
||||
{
|
||||
NSString *s;
|
||||
id o;
|
||||
|
||||
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y%m%dT%H%M%SZ"];
|
||||
// We force parsing in the GMT timezone. If we don't do that, the date will be parsed
|
||||
// in the default timezone.
|
||||
s = [NSString stringWithFormat: @"%@ GMT", self];
|
||||
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y%m%dT%H%M%SZ %Z"];
|
||||
|
||||
if (!o)
|
||||
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ"];
|
||||
|
||||
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ %Z"];
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
@@ -531,6 +531,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (void) processSyncGetChanges: (id <DOMElement>) theDocumentElement
|
||||
inCollection: (id) theCollection
|
||||
withWindowSize: (unsigned int) theWindowSize
|
||||
withMaxSyncResponseSize: (unsigned int) theMaxSyncResponseSize
|
||||
withSyncKey: (NSString *) theSyncKey
|
||||
withFolderType: (SOGoMicrosoftActiveSyncFolderType) theFolderType
|
||||
withFilterType: (NSCalendarDate *) theFilterType
|
||||
@@ -562,7 +563,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
dateCache = [folderMetadata objectForKey: @"DateCache"];
|
||||
|
||||
if ((theFolderType == ActiveSyncMailFolder || theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder) &&
|
||||
!([folderMetadata objectForKey: @"MoreAvailable"]) && // previous sync operation reached the windowSize
|
||||
!([folderMetadata objectForKey: @"MoreAvailable"]) && // previous sync operation reached the windowSize or maximumSyncReponseSize
|
||||
!([theSyncKey isEqualToString: @"-1"]) && // new sync operation
|
||||
theFilterType)
|
||||
{
|
||||
@@ -590,7 +591,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
softdelete_count++;
|
||||
}
|
||||
|
||||
if (softdelete_count >= theWindowSize)
|
||||
if (softdelete_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
|
||||
{
|
||||
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
|
||||
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
||||
@@ -653,7 +654,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Check for the WindowSize and slice accordingly
|
||||
if (return_count >= theWindowSize)
|
||||
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
|
||||
{
|
||||
more_available = YES;
|
||||
|
||||
@@ -668,7 +669,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
deleted = [[component objectForKey: @"c_deleted"] intValue];
|
||||
|
||||
if (!deleted && ![[component objectForKey: @"c_component"] isEqualToString: component_name])
|
||||
continue;
|
||||
{
|
||||
DESTROY(pool);
|
||||
continue;
|
||||
}
|
||||
|
||||
uid = [[component objectForKey: @"c_name"] sanitizedServerIdWithType: theFolderType];
|
||||
|
||||
@@ -692,10 +696,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if (![syncCache objectForKey: uid])
|
||||
updated = NO;
|
||||
else if ([[component objectForKey: @"c_lastmodified"] intValue] == [[syncCache objectForKey: uid] intValue])
|
||||
continue;
|
||||
{
|
||||
DESTROY(pool);
|
||||
continue;
|
||||
}
|
||||
|
||||
return_count++;
|
||||
|
||||
|
||||
sogoObject = [theCollection lookupName: [uid sanitizedServerIdWithType: theFolderType]
|
||||
inContext: context
|
||||
acquire: 0];
|
||||
@@ -705,7 +712,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else
|
||||
componentObject = [sogoObject component: NO secure: NO];
|
||||
|
||||
|
||||
//
|
||||
// We do NOT synchronize NEW events that are in fact, invitations
|
||||
// to events. This is due to the fact that Outlook 2013 creates
|
||||
@@ -732,17 +738,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
|
||||
[syncCache setObject: [component objectForKey: @"c_lastmodified"] forKey: uid];
|
||||
|
||||
// No need to set dateCache for Contacts
|
||||
if ((theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder))
|
||||
{
|
||||
NSCalendarDate *d;
|
||||
|
||||
if ([[component objectForKey: @"c_cycleenddate"] intValue])
|
||||
d = [NSCalendarDate dateWithTimeIntervalSince1970: [[component objectForKey: @"c_cycleenddate"] intValue]];
|
||||
else if ([[component objectForKey: @"c_enddate"] intValue])
|
||||
d = [NSCalendarDate dateWithTimeIntervalSince1970: [[component objectForKey: @"c_enddate"] intValue]];
|
||||
else
|
||||
d = [NSCalendarDate distantFuture];
|
||||
|
||||
[dateCache setObject: d forKey: uid];
|
||||
}
|
||||
|
||||
if (updated)
|
||||
[s appendString: @"<Change xmlns=\"AirSync:\">"];
|
||||
else
|
||||
{
|
||||
// no need to set dateCache for Contacts
|
||||
if ((theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder))
|
||||
[dateCache setObject: [componentObject startDate] ? [componentObject startDate] : [NSCalendarDate date] forKey: uid]; // FIXME: need to set proper date for recurring events - softDelete
|
||||
|
||||
[s appendString: @"<Add xmlns=\"AirSync:\">"];
|
||||
}
|
||||
|
||||
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
|
||||
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
|
||||
@@ -829,7 +844,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else
|
||||
found_in_cache = NO;
|
||||
|
||||
|
||||
if (found_in_cache)
|
||||
k = j+1;
|
||||
else
|
||||
@@ -847,7 +861,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Check for the WindowSize and slice accordingly
|
||||
if (return_count >= theWindowSize)
|
||||
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
|
||||
{
|
||||
NSString *lastSequence;
|
||||
more_available = YES;
|
||||
@@ -1047,6 +1061,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (void) processSyncCollection: (id <DOMElement>) theDocumentElement
|
||||
inBuffer: (NSMutableString *) theBuffer
|
||||
changeDetected: (BOOL *) changeDetected
|
||||
maxSyncResponseSize: (int) theMaxSyncResponseSize
|
||||
{
|
||||
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *lastServerKey;
|
||||
SOGoMicrosoftActiveSyncFolderType folderType;
|
||||
@@ -1076,7 +1091,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//[theBuffer appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
|
||||
//[theBuffer appendFormat: @"<Status>%d</Status>", 8];
|
||||
//[theBuffer appendString: @"</Collection>"];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1139,6 +1153,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self processSyncGetChanges: theDocumentElement
|
||||
inCollection: collection
|
||||
withWindowSize: windowSize
|
||||
withMaxSyncResponseSize: theMaxSyncResponseSize
|
||||
withSyncKey: syncKey
|
||||
withFolderType: folderType
|
||||
withFilterType: [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]]
|
||||
@@ -1324,15 +1339,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSArray *allCollections;
|
||||
NSData *d;
|
||||
|
||||
int i, j, defaultInterval, heartbeatInterval, internalInterval;
|
||||
int i, j, defaultInterval, heartbeatInterval, internalInterval, maxSyncResponseSize;
|
||||
BOOL changeDetected;
|
||||
|
||||
changeDetected = NO;
|
||||
|
||||
maxSyncResponseSize = [[SOGoSystemDefaults sharedSystemDefaults] maximumSyncResponseSize];
|
||||
|
||||
// We initialize our output buffer
|
||||
output = [[NSMutableString alloc] init];
|
||||
|
||||
[output appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||
[output appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||
[output appendString: @"<Sync xmlns=\"AirSync:\">"];
|
||||
|
||||
//
|
||||
// We don't support yet empty Sync requests. See: http://msdn.microsoft.com/en-us/library/ee203280(v=exchg.80).aspx
|
||||
// We return '13' - see http://msdn.microsoft.com/en-us/library/gg675457(v=exchg.80).aspx
|
||||
//
|
||||
if (!theDocumentElement || [[(id)[theDocumentElement getElementsByTagName: @"Partial"] lastObject] textValue])
|
||||
{
|
||||
[output appendString: @"<Status>13</Status>"];
|
||||
[output appendString: @"</Sync>"];
|
||||
d = [[output dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
||||
[theResponse setContent: d];
|
||||
return;
|
||||
}
|
||||
|
||||
defaults = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
heartbeatInterval = [[[(id)[theDocumentElement getElementsByTagName: @"HeartbeatInterval"] lastObject] textValue] intValue];
|
||||
@@ -1363,7 +1395,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
aCollection = [allCollections objectAtIndex: j];
|
||||
|
||||
[self processSyncCollection: aCollection inBuffer: s changeDetected: &changeDetected];
|
||||
[self processSyncCollection: aCollection
|
||||
inBuffer: s
|
||||
changeDetected: &changeDetected
|
||||
maxSyncResponseSize: maxSyncResponseSize];
|
||||
}
|
||||
|
||||
if (changeDetected)
|
||||
@@ -1378,21 +1413,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
}
|
||||
|
||||
// We always return the last generated response.
|
||||
// If we only return <Sync><Collections/></Sync>,
|
||||
// iOS powered devices will simply crash.
|
||||
[output appendString: s];
|
||||
// Only send a response if there are changes otherwise send an empty response.
|
||||
if (changeDetected)
|
||||
{
|
||||
// We always return the last generated response.
|
||||
// If we only return <Sync><Collections/></Sync>,
|
||||
// iOS powered devices will simply crash.
|
||||
[output appendString: s];
|
||||
|
||||
[output appendString: @"</Collections></Sync>"];
|
||||
[output appendString: @"</Collections></Sync>"];
|
||||
|
||||
d = [output dataUsingEncoding: NSUTF8StringEncoding];
|
||||
d = [d xml2wbxml];
|
||||
[theResponse setContent: d];
|
||||
}
|
||||
|
||||
// Avoid overloading the autorelease pool here, as Sync command can
|
||||
// generate fairly large responses.
|
||||
d = [output dataUsingEncoding: NSUTF8StringEncoding];
|
||||
RELEASE(output);
|
||||
|
||||
d = [d xml2wbxml];
|
||||
|
||||
[theResponse setContent: d];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -793,10 +793,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
cKey = [allKeys objectAtIndex: i];
|
||||
|
||||
// ignore invalid folder in cache caused by fs code bugs
|
||||
if ([cKey isEqualToString:@"(null)"])
|
||||
continue;
|
||||
|
||||
// if a cache entry is not found in imapGUIDs its either an imap which has been deleted or its an other folder type which can be checked via lookupName.
|
||||
if (![imapGUIDs allKeysForObject: cKey])
|
||||
{
|
||||
@@ -807,7 +803,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
|
||||
if ([cKey hasPrefix: @"folder"])
|
||||
if ([cKey hasPrefix: @"folder"] || [cKey isEqualToString:@"(null)"])
|
||||
{
|
||||
[commands appendFormat: @"<Delete><ServerId>%@</ServerId></Delete>", [[NSString stringWithFormat: @"mail/%@", [cKey substringFromIndex: 6]] stringByEscapingURL]] ;
|
||||
command_count++;
|
||||
@@ -849,6 +845,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
folderMetadata = [allFoldersMetadata objectAtIndex: i];
|
||||
|
||||
nameInCache = [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]];
|
||||
|
||||
// we have no guid - ignore the folder
|
||||
if (![imapGUIDs objectForKey: nameInCache])
|
||||
continue;
|
||||
|
||||
serverId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: nameInCache] substringFromIndex: 6]];
|
||||
name = [folderMetadata objectForKey: @"displayName"];
|
||||
|
||||
@@ -2480,8 +2481,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
// We check if it's a Ping command with no body.
|
||||
// See http://msdn.microsoft.com/en-us/library/ee200913(v=exchg.80).aspx for details
|
||||
if ([cmdName caseInsensitiveCompare: @"Ping"] != NSOrderedSame && [cmdName caseInsensitiveCompare: @"GetAttachment"] != NSOrderedSame)
|
||||
return [NSException exceptionWithHTTPStatus: 500];
|
||||
if ([cmdName caseInsensitiveCompare: @"Ping"] != NSOrderedSame && [cmdName caseInsensitiveCompare: @"GetAttachment"] != NSOrderedSame && [cmdName caseInsensitiveCompare: @"Sync"] != NSOrderedSame)
|
||||
{
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return [NSException exceptionWithHTTPStatus: 500];
|
||||
}
|
||||
}
|
||||
|
||||
if (d)
|
||||
|
||||
@@ -55,7 +55,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[o setUID: theUID];
|
||||
[o setSequence: theSequence];
|
||||
|
||||
return o;
|
||||
return [o autorelease];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
|
||||
@@ -332,7 +332,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
NSInteger tzOffset;
|
||||
BOOL isAllDay;
|
||||
|
||||
if ((o = [theValues objectForKey: @"UID"]))
|
||||
@@ -384,10 +383,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Some Windows devices don't send during event updates.
|
||||
//if ((o = [theValues objectForKey: @"TimeZone"]))
|
||||
// {
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
//}
|
||||
// }
|
||||
//else
|
||||
{
|
||||
// We haven't received a timezone, let's use the user's timezone
|
||||
// specified in SOGo for now.
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
}
|
||||
|
||||
// FIXME: merge with iCalToDo
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
@@ -402,21 +406,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
[start setTimeZone: tz];
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
if (isAllDay)
|
||||
{
|
||||
[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];
|
||||
}
|
||||
}
|
||||
@@ -429,19 +425,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,8 +143,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
NSInteger tzOffset;
|
||||
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
@@ -165,10 +163,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
o = [o calendarDate];
|
||||
completed = (iCalDateTime *) [self uniqueChildWithTag: @"completed"];
|
||||
//tzOffset = [[o timeZone] secondsFromGMTForDate: o];
|
||||
//o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
// hours: 0 minutes: 0
|
||||
// seconds: -tzOffset];
|
||||
[completed setDate: o];
|
||||
[self setStatus: @"COMPLETED"];
|
||||
}
|
||||
@@ -177,15 +171,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
iCalDateTime *due;
|
||||
|
||||
|
||||
o = [o calendarDate];
|
||||
due = (iCalDateTime *) [self uniqueChildWithTag: @"due"];
|
||||
[due setTimeZone: tz];
|
||||
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[due setDateTime: o];
|
||||
}
|
||||
|
||||
|
||||
137
ChangeLog
137
ChangeLog
@@ -1,3 +1,122 @@
|
||||
commit ead665de85e2202dbde926c316cbba927d38dfa7
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 29 16:19:10 2014 -0500
|
||||
|
||||
fix tz issue when the user one was different from the system one with EAS
|
||||
|
||||
M ActiveSync/NSString+ActiveSync.m
|
||||
M ActiveSync/iCalEvent+ActiveSync.m
|
||||
M ActiveSync/iCalToDo+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit a0c1ce8f3b7c22002661d40c24e95a1233b6a6e8
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 29 12:43:20 2014 -0500
|
||||
|
||||
Improved handling of non-existant vs. subscribed folders over EAS
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M SoObjects/Mailer/SOGoMailAccount.m
|
||||
M SoObjects/Mailer/SOGoMailFolder.m
|
||||
|
||||
commit 204a62aa6ac8feb5a13d5a2ee162bb26cc495a50
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Dec 23 10:25:53 2014 -0500
|
||||
|
||||
Improved comments in the code
|
||||
|
||||
M SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
|
||||
commit 31cffdffd34429d1f4873d07d67e822bff82b7cf
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Dec 23 10:24:16 2014 -0500
|
||||
|
||||
Fix freebusy info not always returned
|
||||
|
||||
M NEWS
|
||||
M SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
M SoObjects/SOGo/SOGoFolder.h
|
||||
M SoObjects/SOGo/SOGoFolder.m
|
||||
|
||||
commit 255bcbe92fa6b4610edf5f4d05c97b74537ecb6e
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 22 19:59:33 2014 -0500
|
||||
|
||||
Fixed memory leaks in SOGoSyncCacheObject and correctly kill the cache upon each EAS iteration
|
||||
|
||||
M ActiveSync/SOGoSyncCacheObject.m
|
||||
M SoObjects/Mailer/SOGoMailBaseObject.m
|
||||
M SoObjects/SOGo/NSObject+Utilities.m
|
||||
M UI/MainUI/SOGoMicrosoftActiveSyncActions.m
|
||||
|
||||
commit 72732879fafe8ef928593c0cf3e39d962b096ec9
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 22 19:32:17 2014 -0500
|
||||
|
||||
Added memory statistics - set SOGoDebugLeaks = YES and call [[self class] memoryStatistics]
|
||||
|
||||
M SoObjects/SOGo/NSObject+Utilities.h
|
||||
M SoObjects/SOGo/NSObject+Utilities.m
|
||||
|
||||
commit 24a934275f5678f7ab86cb706aa817dfb5ef8991
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 22 16:12:26 2014 -0500
|
||||
|
||||
Fix small memory leak incase of errors
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
|
||||
commit 58f634bffe35b3a1f6a02072ba0103fea2155a45
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 22 15:26:22 2014 -0500
|
||||
|
||||
Cosmetic improvements to the code
|
||||
|
||||
M SoObjects/Appointments/SOGoAppointmentObject.m
|
||||
M SoObjects/SOGo/SOGoMailer.h
|
||||
M SoObjects/SOGo/SOGoMailer.m
|
||||
|
||||
commit ca4a754f2c12784ff437df34c255d3dccbf5c6f2
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 22 12:39:58 2014 -0500
|
||||
|
||||
Use the right cutoff date
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M NEWS
|
||||
M SoObjects/SOGo/SOGoGCSFolder.m
|
||||
|
||||
commit 8015688df31a3e3254093b260851d4664d725ea6
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 22 11:50:51 2014 -0500
|
||||
|
||||
Added SOGoMaximumSyncResponseSize to support memory-limited EAS syncs
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
M NEWS
|
||||
M SoObjects/SOGo/SOGoSystemDefaults.h
|
||||
M SoObjects/SOGo/SOGoSystemDefaults.m
|
||||
|
||||
commit b07913d66d4a47919e09cbcd0c41d92bd97ea0a3
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 22 08:36:55 2014 -0500
|
||||
|
||||
See NEWS file
|
||||
|
||||
M ActiveSync/NGVCard+ActiveSync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
|
||||
commit df8a0d8715d97873e782ccfbfaab8b580c88c66e
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Fri Dec 19 09:03:37 2014 -0500
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
M ChangeLog
|
||||
|
||||
commit e6cc56dca1126e09cb8336bdbd4e5dabc7b83cf1
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Fri Dec 19 09:03:19 2014 -0500
|
||||
@@ -15,6 +134,24 @@ Date: Fri Dec 19 09:01:39 2014 -0500
|
||||
M NEWS
|
||||
M SoObjects/Mailer/SOGoDraftObject.m
|
||||
|
||||
commit 0e56527e05566e78ac8fe4687d19423de78b0276
|
||||
Author: Chris Rosenhain <chris@rosenha.in>
|
||||
Date: Fri Dec 19 11:04:05 2014 +1030
|
||||
|
||||
Change ACL modification text to non-gender specific terms
|
||||
|
||||
M SoObjects/Appointments/SOGoAppointmentObject.m
|
||||
M SoObjects/Appointments/SOGoCalendarComponent.m
|
||||
M SoObjects/SOGo/SOGoGCSFolder.m
|
||||
M SoObjects/SOGo/SOGoUserFolder.h
|
||||
M UI/MainUI/SOGoRootPage.m
|
||||
M UI/Templates/SOGoACLDanishModificationAdvisory.wox
|
||||
M UI/Templates/SOGoACLDanishRemovalAdvisory.wox
|
||||
M UI/Templates/SOGoACLDutchModificationAdvisory.wox
|
||||
M UI/Templates/SOGoACLDutchRemovalAdvisory.wox
|
||||
M UI/Templates/SOGoACLEnglishModificationAdvisory.wox
|
||||
M UI/Templates/SOGoACLEnglishRemovalAdvisory.wox
|
||||
|
||||
commit db911f323d23f263f5fa9c5fb02d8234127687b3
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Dec 18 08:56:23 2014 -0500
|
||||
|
||||
@@ -2390,6 +2390,15 @@ _SOGoMaximumPingInterval_.
|
||||
|
||||
If not set, it defaults to `10` seconds.
|
||||
|
||||
|S |SOGoMaximumSyncResponseSize
|
||||
|Parameter used to overwrite the maximum response size during
|
||||
a Sync operation. The value is in kilobytes. Setting this to 512
|
||||
means the response size will be of 524288 bytes or less. Note that
|
||||
if you set the value too low and a mail message (or any other object)
|
||||
surpasses it, it will still be synced but only this item will be.
|
||||
|
||||
Defaults to `0`, which means no overwrite is performed.
|
||||
|
||||
|S |SOGoMaximumSyncWindowSize
|
||||
|Parameter used to overwrite the maximum number of items returned during
|
||||
a Sync operation.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- TODO have the build system take care of this -->
|
||||
<releaseinfo>Version 2.2.12 - December 2014</releaseinfo>
|
||||
<subtitle>for version 2.2.12</subtitle>
|
||||
<date>2014-12-18</date>
|
||||
<releaseinfo>Version 2.2.13 - December 2014</releaseinfo>
|
||||
<subtitle>for version 2.2.13</subtitle>
|
||||
<date>2014-12-30</date>
|
||||
|
||||
<legalnotice>
|
||||
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
|
||||
// TODO have the build system take care of this
|
||||
|
||||
:release_version: 2.2.12
|
||||
:release_version: 2.2.13
|
||||
|
||||
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
|
||||
|
||||
14
NEWS
14
NEWS
@@ -1,3 +1,17 @@
|
||||
2.2.13 (2014-12-30)
|
||||
-------------------
|
||||
|
||||
Bug fixes
|
||||
- fix contact description truncation on WP8 phones (#3028)
|
||||
- fix freebusy information not always returned
|
||||
- fix tz issue when the user one was different from the system one with EAS
|
||||
|
||||
Enhancements
|
||||
- initial support for empty sync request/response for EAS
|
||||
- added the SOGoMaximumSyncResponseSize EAS configuration parameter to
|
||||
support memory-limited sync response sizes
|
||||
- we now not only use the creation date for event's cutoff date (EAS)
|
||||
|
||||
2.2.12a (2014-12-19)
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -492,6 +492,9 @@ static Class iCalEventK = nil;
|
||||
//
|
||||
// If the user is NOT the owner of the calendar, by default we exclude the freebusy information.
|
||||
//
|
||||
// We must include the freebusy information of other users if we are actually looking at their freebusy information
|
||||
// but we aren't necessarily subscribed to their calendars.
|
||||
//
|
||||
- (BOOL) includeInFreeBusy
|
||||
{
|
||||
NSNumber *excludeFromFreeBusy;
|
||||
@@ -500,16 +503,31 @@ static Class iCalEventK = nil;
|
||||
|
||||
userLogin = [[context activeUser] login];
|
||||
is_owner = [userLogin isEqualToString: [self ownerInContext: context]];
|
||||
|
||||
|
||||
// Check if the owner (not the active user) has excluded the calendar from her/his free busy data.
|
||||
excludeFromFreeBusy
|
||||
= [self folderPropertyValueInCategory: @"FreeBusyExclusions"
|
||||
forUser: [SOGoUser userWithLogin: userLogin]];
|
||||
|
||||
if (!excludeFromFreeBusy && !is_owner)
|
||||
return NO;
|
||||
|
||||
return ![excludeFromFreeBusy boolValue];
|
||||
if ([self isSubscription])
|
||||
{
|
||||
// If the user has not yet set an include/not include fb information let's EXCLUDE it.
|
||||
if (!excludeFromFreeBusy)
|
||||
return NO;
|
||||
else
|
||||
return ![excludeFromFreeBusy boolValue];
|
||||
}
|
||||
else if (is_owner)
|
||||
{
|
||||
// We are the owner but we haven't included/excluded freebusy info, let's INCLUDE it.
|
||||
if (!excludeFromFreeBusy)
|
||||
return YES;
|
||||
else
|
||||
return ![excludeFromFreeBusy boolValue];
|
||||
}
|
||||
|
||||
// It's not a subscribtion and we aren't the owner. Let's INCLUDE the freebusy info.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) setIncludeInFreeBusy: (BOOL) newInclude
|
||||
|
||||
@@ -400,9 +400,9 @@
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
if (currentUID)
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
owner: owner];
|
||||
}
|
||||
|
||||
[self sendEMailUsingTemplateNamed: @"Update"
|
||||
@@ -443,7 +443,7 @@
|
||||
us = [user userSettings];
|
||||
moduleSettings = [us objectForKey:@"Calendar"];
|
||||
|
||||
// Check if the user prevented his account from beeing invited to events
|
||||
// Check if the user prevented their account from beeing invited to events
|
||||
if (![user isResource] && [[moduleSettings objectForKey:@"PreventInvitations"] boolValue])
|
||||
{
|
||||
// Check if the user have a whiteList
|
||||
@@ -734,7 +734,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
// the modification was actually NOT made on the master event
|
||||
if ([theEvent recurrenceId])
|
||||
return;
|
||||
|
||||
|
||||
events = [[theEvent parent] events];
|
||||
|
||||
for (i = 0; i < [events count]; i++)
|
||||
@@ -743,12 +743,12 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
if ([e recurrenceId])
|
||||
for (j = 0; j < [theAttendees count]; j++)
|
||||
if (shouldAdd)
|
||||
[e addToAttendees: [theAttendees objectAtIndex: j]];
|
||||
else
|
||||
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
|
||||
[e addToAttendees: [theAttendees objectAtIndex: j]];
|
||||
else
|
||||
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -803,14 +803,17 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
// We insert the attendees in all exception occurences, if
|
||||
// the attendees were added to the master event.
|
||||
[self _addOrDeleteAttendees: addedAttendees
|
||||
inRecurrenceExceptionsForEvent: newEvent
|
||||
add: YES];
|
||||
inRecurrenceExceptionsForEvent: newEvent
|
||||
add: YES];
|
||||
|
||||
if ([changes sequenceShouldBeIncreased])
|
||||
{
|
||||
[newEvent increaseSequence];
|
||||
|
||||
// Update attendees calendars and send them an update
|
||||
// notification by email
|
||||
// notification by email. We ignore the newly added
|
||||
// attendees as we don't want to send them invitation
|
||||
// update emails
|
||||
[self _handleSequenceUpdateInEvent: newEvent
|
||||
ignoringAttendees: addedAttendees
|
||||
fromOldEvent: oldEvent];
|
||||
@@ -1093,7 +1096,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
else
|
||||
{
|
||||
// We must REMOVE any SENT-BY here. This is important since if A accepted
|
||||
// the event for B and then, B changes by himself his participation status,
|
||||
// the event for B and then, B changes by theirself their participation status,
|
||||
// we don't want to keep the previous SENT-BY attribute there.
|
||||
[(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"];
|
||||
}
|
||||
@@ -1191,7 +1194,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
else
|
||||
{
|
||||
// We must REMOVE any SENT-BY here. This is important since if A accepted
|
||||
// the event for B and then, B changes by himself his participation status,
|
||||
// the event for B and then, B changes by theirself their participation status,
|
||||
// we don't want to keep the previous SENT-BY attribute there.
|
||||
[(NSMutableDictionary *)[attendee attributes] removeObjectForKey: @"SENT-BY"];
|
||||
}
|
||||
@@ -1208,7 +1211,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
|
||||
delegatedUID = [otherDelegate uid];
|
||||
if (delegatedUID)
|
||||
// Delegate attendee is a local user; remove event from his calendar
|
||||
// Delegate attendee is a local user; remove event from their calendar
|
||||
[self _removeEventFromUID: delegatedUID
|
||||
owner: [theOwnerUser login]
|
||||
withRecurrenceId: [event recurrenceId]];
|
||||
@@ -1240,7 +1243,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
[event addToAttendees: delegate];
|
||||
|
||||
if (delegatedUID)
|
||||
// Delegate attendee is a local user; add event to his calendar
|
||||
// Delegate attendee is a local user; add event to their calendar
|
||||
[self _addOrUpdateEvent: event
|
||||
forUID: delegatedUID
|
||||
owner: [theOwnerUser login]];
|
||||
|
||||
@@ -644,8 +644,8 @@
|
||||
// As much as we can, we try to use c_name == c_uid in order
|
||||
// to avoid tricky scenarios with some CalDAV clients. For example,
|
||||
// if Alice invites Bob (both use SOGo) and Bob accepts the invitation
|
||||
// using Lightning before having refreshed his calendar, he'll end up
|
||||
// with a duplicate of the event in his database tables.
|
||||
// using Lightning before having refreshed their calendar, they'll end up
|
||||
// with a duplicate of the event in their database tables.
|
||||
if (isNew)
|
||||
{
|
||||
newUid = nameInContainer;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#import <NGImap4/NGImap4Connection.h>
|
||||
#import <NGImap4/NGImap4Client.h>
|
||||
#import <NGImap4/NGImap4Context.h>
|
||||
#import <NGImap4/NSString+Imap4.h>
|
||||
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
@@ -667,19 +668,14 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
NSDictionary *result, *nresult, *namespaceDict;
|
||||
NSMutableDictionary *folders;
|
||||
NGImap4Client *client;
|
||||
SOGoUserDefaults *ud;
|
||||
NSArray *folderList;
|
||||
NSEnumerator *e;
|
||||
NSString *guid;
|
||||
id object;
|
||||
|
||||
BOOL subscribedOnly, hasAnnotatemore;
|
||||
BOOL hasAnnotatemore;
|
||||
|
||||
ud = [[context activeUser] userDefaults];
|
||||
subscribedOnly = [ud mailShowSubscribedFoldersOnly];
|
||||
|
||||
folderList = [[self imap4Connection] allFoldersForURL: [self imap4URL]
|
||||
onlySubscribedFolders: subscribedOnly];
|
||||
folderList = [self allFolderPaths];
|
||||
|
||||
folders = [NSMutableDictionary dictionary];
|
||||
|
||||
@@ -688,19 +684,19 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
hasAnnotatemore = [self hasCapability: @"annotatemore"];
|
||||
|
||||
if (hasAnnotatemore)
|
||||
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
|
||||
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
|
||||
else
|
||||
result = [client lstatus: @"*" flags: [NSArray arrayWithObjects: @"x-guid", nil]];
|
||||
|
||||
result = [client lstatus: @"*" flags: [NSArray arrayWithObjects: @"x-guid", nil]];
|
||||
|
||||
e = [folderList objectEnumerator];
|
||||
|
||||
|
||||
while ((object = [e nextObject]))
|
||||
{
|
||||
if (hasAnnotatemore)
|
||||
guid = [[[[result objectForKey: @"FolderList"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"/comment"] objectForKey: @"value.priv"];
|
||||
guid = [[[[result objectForKey: @"FolderList"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"/comment"] objectForKey: @"value.priv"];
|
||||
else
|
||||
guid = [[[result objectForKey: @"status"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"x-guid"];
|
||||
|
||||
guid = [[[result objectForKey: @"status"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"x-guid"];
|
||||
|
||||
if (!guid)
|
||||
{
|
||||
// Don't generate a GUID for "Other users" and "Shared" namespace folders - user foldername instead
|
||||
@@ -710,18 +706,28 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
[folders setObject: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]] forKey: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]]];
|
||||
continue;
|
||||
}
|
||||
|
||||
guid = [[NSProcessInfo processInfo] globallyUniqueString];
|
||||
nresult = [client annotation: [object substringFromIndex: 1] entryName: @"/comment" attributeName: @"value.priv" attributeValue: guid];
|
||||
|
||||
if (![[nresult objectForKey: @"result"] boolValue])
|
||||
guid = [NSString stringWithFormat: @"%@", [object substringFromIndex: 1]];
|
||||
// if folder doesn't exists - ignore it
|
||||
nresult = [client status: [object substringFromIndex: 1]
|
||||
flags: [NSArray arrayWithObject: @"UIDVALIDITY"]];
|
||||
if (![[nresult valueForKey: @"result"] boolValue])
|
||||
continue;
|
||||
|
||||
if (hasAnnotatemore)
|
||||
{
|
||||
guid = [[NSProcessInfo processInfo] globallyUniqueString];
|
||||
nresult = [client annotation: [object substringFromIndex: 1] entryName: @"/comment" attributeName: @"value.priv" attributeValue: guid];
|
||||
}
|
||||
|
||||
// setannotation failed or annotatemore is not available
|
||||
if (![[nresult objectForKey: @"result"] boolValue] || !hasAnnotatemore)
|
||||
guid = [NSString stringWithFormat: @"%@", [object substringFromIndex: 1]];
|
||||
}
|
||||
|
||||
|
||||
[folders setObject: [NSString stringWithFormat: @"folder%@", guid] forKey: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]]];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,10 +43,6 @@
|
||||
|
||||
@implementation SOGoMailBaseObject
|
||||
|
||||
#if 0
|
||||
static BOOL debugOn = YES;
|
||||
#endif
|
||||
|
||||
- (id) initWithImap4URL: (NSURL *) _url
|
||||
inContainer: (id) _container
|
||||
{
|
||||
|
||||
@@ -1069,7 +1069,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
NSException *error;
|
||||
|
||||
if ([self imap4Connection])
|
||||
error = [imap4 deleteMailboxAtURL: [self imap4URL]];
|
||||
{
|
||||
error = [imap4 deleteMailboxAtURL: [self imap4URL]];
|
||||
if (!error)
|
||||
[[imap4 client] unsubscribe: [[self imap4URL] path]];
|
||||
}
|
||||
else
|
||||
error = [NSException exceptionWithName: @"SOGoMailException"
|
||||
reason: @"IMAP connection is invalid"
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
- (NSString *) labelForKey: (NSString *) key
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
+ (void) memoryStatistics;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* NSOBJECT+UTILITIES_H */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSBundle.h>
|
||||
#import <Foundation/NSDebug.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
@@ -122,4 +123,33 @@
|
||||
return label;
|
||||
}
|
||||
|
||||
//
|
||||
// Set SOGoDebugLeaks = YES in your defaults to enable.
|
||||
//
|
||||
+ (void) memoryStatistics
|
||||
{
|
||||
Class *classList = GSDebugAllocationClassList ();
|
||||
Class *pointer;
|
||||
int i, count, total, peak;
|
||||
NSString *className;
|
||||
|
||||
pointer = classList;
|
||||
i = 0;
|
||||
|
||||
printf("Class count total peak\n");
|
||||
while (pointer[i] != NULL)
|
||||
{
|
||||
className = NSStringFromClass (pointer[i]);
|
||||
count = GSDebugAllocationCount (pointer[i]);
|
||||
total = GSDebugAllocationTotal (pointer[i]);
|
||||
peak = GSDebugAllocationPeak (pointer[i]);
|
||||
|
||||
printf("%s %d %d %d\n", [className UTF8String], count, total, peak);
|
||||
i++;
|
||||
}
|
||||
NSZoneFree(NSDefaultMallocZone(), classList);
|
||||
|
||||
printf("Done!\n");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SOGoFolder.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2013 Inverse inc.
|
||||
* Copyright (C) 2007-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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoFolder.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2011 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2007-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
|
||||
|
||||
@@ -302,7 +302,7 @@ static NSArray *childRecordFields = nil;
|
||||
}
|
||||
|
||||
/* This method fetches the display name defined by the owner, but is also the
|
||||
fallback when a subscriber has not redefined the display name yet in his
|
||||
fallback when a subscriber has not redefined the display name yet in their
|
||||
environment. */
|
||||
- (NSString *) _displayNameFromOwner
|
||||
{
|
||||
@@ -895,7 +895,7 @@ static NSArray *childRecordFields = nil;
|
||||
allUsers = [NSMutableArray arrayWithArray: [aGroup members]];
|
||||
|
||||
// We remove the active user from the group (if present) in order to
|
||||
// not subscribe him to his own resource!
|
||||
// not subscribe him to their own resource!
|
||||
[allUsers removeObject: [context activeUser]];
|
||||
}
|
||||
else
|
||||
@@ -1165,7 +1165,14 @@ static NSArray *childRecordFields = nil;
|
||||
int syncTokenInt;
|
||||
|
||||
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_component",
|
||||
@"c_creationdate", @"c_lastmodified", nil];
|
||||
@"c_creationdate", @"c_lastmodified", nil];
|
||||
|
||||
if ([[self folderType] isEqualToString: @"Appointment"])
|
||||
{
|
||||
[fields addObject: @"c_enddate"];
|
||||
[fields addObject: @"c_cycleenddate"];
|
||||
}
|
||||
|
||||
addFields = [[properties allValues] objectEnumerator];
|
||||
while ((currentField = [addFields nextObject]))
|
||||
if ([currentField length])
|
||||
@@ -1181,7 +1188,9 @@ static NSArray *childRecordFields = nil;
|
||||
if (theStartDate)
|
||||
{
|
||||
EOQualifier *sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"c_creationdate > %d", (int)[theStartDate timeIntervalSince1970]];
|
||||
@"(c_enddate > %d OR c_enddate = NULL) OR (c_iscycle = 1 and (c_cycleenddate > %d OR c_cycleenddate = NULL))",
|
||||
(int)[theStartDate timeIntervalSince1970],
|
||||
(int)[theStartDate timeIntervalSince1970]];
|
||||
|
||||
qualifier = [[EOAndQualifier alloc] initWithQualifiers: sinceDateQualifier, qualifier,
|
||||
nil];
|
||||
@@ -1211,7 +1220,9 @@ static NSArray *childRecordFields = nil;
|
||||
if (theStartDate)
|
||||
{
|
||||
EOQualifier *sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"c_creationdate > %d", (int)[theStartDate timeIntervalSince1970]];
|
||||
@"(c_enddate > %d OR c_enddate = NULL) OR (c_iscycle = 1 and (c_cycleenddate > %d OR c_cycleenddate = NULL))",
|
||||
(int)[theStartDate timeIntervalSince1970],
|
||||
(int)[theStartDate timeIntervalSince1970]];
|
||||
|
||||
qualifier = [[EOAndQualifier alloc] initWithQualifiers: sinceDateQualifier, qualifier,
|
||||
nil];
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoMailer.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2007-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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoMailer.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2013 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2007-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
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
- (int) maximumSyncInterval;
|
||||
- (int) internalSyncInterval;
|
||||
- (int) maximumSyncWindowSize;
|
||||
- (int) maximumSyncResponseSize;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -636,4 +636,16 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
|
||||
return [self integerForKey: @"SOGoMaximumSyncWindowSize"];
|
||||
}
|
||||
|
||||
- (int) maximumSyncResponseSize
|
||||
{
|
||||
int v;
|
||||
|
||||
v = [self integerForKey: @"SOGoMaximumSyncResponseSize"];
|
||||
|
||||
if (v > 0)
|
||||
v = v * 1024;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
Child objects:
|
||||
'Calendar': SOGoAppointmentFolder
|
||||
|
||||
The SOGoUserFolder is the "home directory" of the user where all his
|
||||
The SOGoUserFolder is the "home directory" of the user where all their
|
||||
processing starts. It is the 'znek' in such a path:
|
||||
/SOGo/so/znek/Calendar
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#import <Foundation/NSBundle.h>
|
||||
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/NSObject+Utilities.h>
|
||||
#import <SOGo/SOGoFolder.h>
|
||||
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
@@ -54,13 +56,17 @@
|
||||
|
||||
ex = [dispatcher dispatchRequest: request inResponse: response context: context];
|
||||
|
||||
//[[self class] memoryStatistics];
|
||||
|
||||
if (ex)
|
||||
{
|
||||
return [NSException exceptionWithHTTPStatus: 500];
|
||||
}
|
||||
|
||||
RELEASE(dispatcher);
|
||||
|
||||
|
||||
[[SOGoCache sharedCache] killCache];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@
|
||||
|
||||
if (login)
|
||||
{
|
||||
/* We redirect the user to his "homepage" when newLocation could not be
|
||||
/* We redirect the user to their "homepage" when newLocation could not be
|
||||
deduced from the "cas-location" cookie and the current action is not a
|
||||
login callback (ticket != nil). */
|
||||
if (!newLocation || !ticket)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isBody">
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<!--
|
||||
You can subscribe directly to that folder by following this link:
|
||||
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>subscribe?mail-invitation=YES
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isBody">
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<!--
|
||||
You can unsubscribe directly to that folder by following this link:
|
||||
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>unsubscribe?mail-invitation=YES
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isBody">
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<!--
|
||||
You can subscribe directly to that folder by following this link:
|
||||
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>subscribe?mail-invitation=YES
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isBody">
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<!--
|
||||
You can unsubscribe directly to that folder by following this link:
|
||||
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>unsubscribe?mail-invitation=YES
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isBody">
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<!--
|
||||
You can subscribe directly to that folder by following this link:
|
||||
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>subscribe?mail-invitation=YES
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</var:if>
|
||||
|
||||
<var:if condition="isBody">
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
|
||||
<!--
|
||||
You can unsubscribe directly to that folder by following this link:
|
||||
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>unsubscribe?mail-invitation=YES
|
||||
|
||||
Reference in New Issue
Block a user