Merge branch 'master-upstream' into jjgarcia/merge-from-upstream

pull/65/head
Julio García 2015-02-02 12:53:49 +01:00
commit 12b159a6c0
695 changed files with 8277 additions and 3680 deletions

View File

@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
@ -193,11 +194,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>"];
}
@ -222,14 +224,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setNote: o];
// Categories
if ((o = [theValues objectForKey: @"Categories"]))
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
[self setCategories: o];
// Birthday
if ((o = [theValues objectForKey: @"Birthday"]))
{
o = [o calendarDate];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d"]];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d" timeZone: nil locale: nil]];
}
//

View File

@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSString.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSObject+Logs.h>
#include <wbxml/wbxml.h>
#include <wbxml/wbxml_conv.h>
@ -48,7 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
NSLog(@"Original data written to: %@", path);
[self errorWithFormat: @"Original data written to: %@", path];
}
//
@ -81,20 +82,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
NSLog(@"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self errorWithFormat: @"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
data = [[NSData alloc] initWithBytes: xml length: xml_len];
data = [NSData dataWithBytesNoCopy: xml length: xml_len freeWhenDone: YES];
#if WBXMLDEBUG
[data writeToFile: @"/tmp/protocol.decoded" atomically: YES];
#endif
free(xml);
return AUTORELEASE(data);
return data;
}
@ -116,7 +115,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self logWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
@ -131,22 +130,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self errorWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
return nil;
}
data = [[NSData alloc] initWithBytes: wbxml length: wbxml_len];
data = [NSData dataWithBytesNoCopy: wbxml length: wbxml_len freeWhenDone: YES];
#if WBXMLDEBUG
[data writeToFile: @"/tmp/protocol.encoded" atomically: YES];
#endif
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
return AUTORELEASE(data);
return data;
}
@end

View File

@ -33,11 +33,17 @@ 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>
#include <NGExtensions/NGBase64Coding.h>
#include <NGExtensions/NSString+misc.h>
static NSArray *easCommandCodes = nil;
static NSArray *easCommandParameters = nil;
@implementation NSString (ActiveSync)
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType
@ -61,9 +67,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
NSString *s;
s = [self stringByEscapingHTMLString];
s = [self safeString];
return [s safeString];
return [s stringByEscapingHTMLString];
}
- (int) activeSyncFolderType
@ -122,23 +128,98 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
- (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;
}
- (NSString *) _valueForParameter: (NSString *) theParameter
{
NSArray *components;
NSMutableArray *components;
NSString *s;
int i;
components = [[[self componentsSeparatedByString: @"?"] lastObject] componentsSeparatedByString: @"&"];
components = [NSMutableArray arrayWithArray: [[[self componentsSeparatedByString: @"?"] lastObject] componentsSeparatedByString: @"&"]];
// We handle BASE64 encoded queryStrings. See http://msdn.microsoft.com/en-us/library/ee160227%28v=exchg.80%29.aspx for details.
if ([components count] == 1)
{
NSString *deviceType, *parameterValue;
NSData *queryString;
int cmd_code, deviceid_length, policy_length, devicetype_length, parameter_code, parameter_length, i;
const char* qs_bytes;
queryString = [[components objectAtIndex: 0] dataByDecodingBase64];
if (![queryString length])
return nil;
qs_bytes = (const char*)[queryString bytes];
if (!easCommandCodes)
{
easCommandCodes = [NSArray arrayWithObjects:@"Sync", @"SendMail", @"SmartForward", @"SmartReply", @"GetAttachment", @"na", @"na", @"na", @"na",
@"FolderSync", @"FolderCreate", @"FolderDelete", @"FolderUpdate", @"MoveItems", @"GetItemEstimate", @"MeetingResponse",
@"Search", @"Settings", @"Ping", @"ItemOperations", @"Provision", @"ResolveRecipients", @"ValidateCert", nil];
RETAIN(easCommandCodes);
}
if (!easCommandParameters)
{
easCommandParameters = [NSArray arrayWithObjects:@"AttachmentName", @"CollectionId", @"na", @"ItemId", @"LongId", @"na", @"Occurrence", @"Options", @"User", nil];
RETAIN(easCommandParameters);
}
// Command code, 1 byte, ie.: cmd=
cmd_code = qs_bytes[1];
[components addObject: [NSString stringWithFormat: @"cmd=%@", [easCommandCodes objectAtIndex: cmd_code]]];
// Device ID length and Device ID (variable)
deviceid_length = qs_bytes[4];
[components addObject: [NSString stringWithFormat: @"deviceId=%@", [[NSData encodeDataAsHexString: [queryString subdataWithRange: NSMakeRange(5, deviceid_length)]] uppercaseString]]];
// Device type length and type (variable)
policy_length = qs_bytes[5+deviceid_length];
devicetype_length = qs_bytes[5+deviceid_length+1+policy_length];
deviceType = [[NSString alloc] initWithData: [queryString subdataWithRange: NSMakeRange(5+deviceid_length+1+policy_length+1, devicetype_length)]
encoding: NSASCIIStringEncoding];
AUTORELEASE(deviceType);
[components addObject: [NSString stringWithFormat: @"deviceType=%@", deviceType]];
// Command Parameters
i = 5+deviceid_length+1+policy_length+1+devicetype_length;
while (i < [queryString length])
{
parameter_code = qs_bytes[i];
parameter_length = qs_bytes[i+1];
parameterValue = [[NSString alloc] initWithData: [queryString subdataWithRange: NSMakeRange(i+1+1, parameter_length)]
encoding: NSASCIIStringEncoding];
AUTORELEASE(parameterValue);
// parameter_code 7 == Options
// http://msdn.microsoft.com/en-us/library/ee237789(v=exchg.80).aspx
if (parameter_code == 7)
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code],
([parameterValue isEqualToString: @"\001"]) ? @"SaveInSent" : @"AcceptMultiPart"]];
else
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code], parameterValue]];
i = i + 1 + 1 + parameter_length;
}
}
for (i = 0; i < [components count]; i++)
{

View File

@ -4,7 +4,7 @@ to negotiate the fees associated to your user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
http://www.microsoft.com/en-us/legal/intellectualproperty/
and send an email to iplicreq@microsoft.com

View File

@ -29,11 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "SOGoActiveSyncDispatcher+Sync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSNull.h>
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSSortDescriptor.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
@ -56,6 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGCards/NGVCard.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NSString+Imap4.h>
@ -114,22 +116,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
forKey: (NSString *) theFolderKey
{
SOGoCacheGCSObject *o;
NSDictionary *values;
NSString *key;
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
values = [theFolderMetadata copy];
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
[o setObjectType: ActiveSyncFolderCacheObject];
[o setTableUrl: [self folderTableURL]];
[o reloadIfNeeded];
//[o reloadIfNeeded];
[[o properties] removeObjectForKey: @"SyncKey"];
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] addEntriesFromDictionary: theFolderMetadata];
[[o properties] addEntriesFromDictionary: values];
[o save];
[values release];
}
- (NSMutableDictionary *) _folderMetadataForKey: (NSString *) theFolderKey
@ -147,6 +153,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return [o properties];
}
- (NSString *) _getNameInCache: (id) theCollection withType: (SOGoMicrosoftActiveSyncFolderType) theFolderType
{
NSString *nameInCache;
if (theFolderType == ActiveSyncMailFolder)
nameInCache= [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]];
else
{
NSString *component_name;
if (theFolderType == ActiveSyncContactFolder)
component_name = @"vcard";
else if (theFolderType == ActiveSyncEventFolder)
component_name = @"vevent";
else
component_name = @"vtodo";
nameInCache= [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]];
}
return nameInCache;
}
//
// <?xml version="1.0"?>
@ -190,7 +219,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
withType: (SOGoMicrosoftActiveSyncFolderType) theFolderType
inBuffer: (NSMutableString *) theBuffer
{
NSMutableDictionary *allValues;
NSMutableDictionary *folderMetadata, *dateCache, *syncCache, *allValues;
NSString *clientId, *serverId;
NSArray *additions;
@ -259,9 +288,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
case ActiveSyncMailFolder:
default:
{
// FIXME
//continue;
NSLog(@"BLARG!");
// FIXME - what to do?
[self errorWithFormat: @"Fatal error occured - tried to call -processSyncAddCommand: ... on a mail folder. We abort."];
abort();
}
}
@ -276,6 +304,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", serverId];
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
[theBuffer appendString: @"</Add>"];
// Update syncCache
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: theCollection withType: theFolderType]];
syncCache = [folderMetadata objectForKey: @"SyncCache"];
dateCache = [folderMetadata objectForKey: @"DateCache"];
[syncCache setObject: [folderMetadata objectForKey: @"SyncKey"] forKey: serverId];
[dateCache setObject: [NSCalendarDate date] forKey: serverId];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
}
}
}
@ -375,6 +414,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
[theBuffer appendString: @"<Change>"];
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", serverId];
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
[theBuffer appendString: @"</Change>"];
}
}
}
@ -431,6 +474,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (![sogoObject isKindOfClass: [NSException class]])
[sogoObject delete];
[theBuffer appendString: @"<Delete>"];
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", serverId];
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
[theBuffer appendString: @"</Delete>"];
// update syncCache
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: theCollection withType: theFolderType]];
syncCache = [folderMetadata objectForKey: @"SyncCache"];
dateCache = [folderMetadata objectForKey: @"DateCache"];
[syncCache removeObjectForKey: serverId];
[dateCache removeObjectForKey: serverId];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
}
}
}
@ -471,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
@ -479,6 +540,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
NSAutoreleasePool *pool;
NSMutableString *s;
BOOL more_available;
@ -488,18 +550,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
more_available = NO;
if (theFolderType == ActiveSyncMailFolder && !([theSyncKey isEqualToString: @"-1"]) && theFilterType)
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: theCollection withType: theFolderType]];
// If this is a new sync operation, DateCache and SyncCache needs to be deleted
if ([theSyncKey isEqualToString: @"-1"])
{
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"SyncCache"];
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"DateCache"];
}
syncCache = [folderMetadata objectForKey: @"SyncCache"];
dateCache = [folderMetadata objectForKey: @"DateCache"];
if ((theFolderType == ActiveSyncMailFolder || theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder) &&
!([folderMetadata objectForKey: @"MoreAvailable"]) && // previous sync operation reached the windowSize or maximumSyncReponseSize
!([theSyncKey isEqualToString: @"-1"]) && // new sync operation
theFilterType)
{
NSArray *allKeys;
NSString *key;
int softdelete_count;
softdelete_count = 0;
folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
dateCache = [folderMetadata objectForKey: @"DateCache"];
syncCache = [folderMetadata objectForKey: @"SyncCache"];
allKeys = [dateCache allKeys];
for (i = 0; i < [allKeys count]; i++)
{
@ -510,17 +584,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @"<SoftDelete xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", key];
[s appendString: @"</SoftDelete>"];
[syncCache removeObjectForKey: key];
[dateCache removeObjectForKey: key];
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: [theCollection nameInContainer]];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
more_available = YES;
*theLastServerKey = theSyncKey;
@ -532,7 +606,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
}
//
@ -557,7 +631,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSArray *allComponents;
BOOL updated;
int deleted;
int deleted, return_count;
if (theFolderType == ActiveSyncContactFolder)
component_name = @"vcard";
@ -567,39 +641,67 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
component_name = @"vtodo";
allComponents = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
allComponents = [allComponents sortedArrayUsingDescriptors: [NSArray arrayWithObjects: [[NSSortDescriptor alloc] initWithKey: @"c_lastmodified" ascending:YES], nil]];
// Check for the WindowSize
max = [allComponents count];
// Disabled for now for GCS folders.
// if (max > theWindowSize)
// {
// max = theWindowSize;
// more_available = YES;
// }
return_count = 0;
for (i = 0; i < max; i++)
{
pool = [[NSAutoreleasePool alloc] init];
// Check for the WindowSize and slice accordingly
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
{
more_available = YES;
// -1 to make sure that we miss no event in case there are more with the same c_lastmodified
*theLastServerKey = [[NSString alloc] initWithFormat: @"%d", [[component objectForKey: @"c_lastmodified"] intValue] - 1];
DESTROY(pool);
break;
}
component = [allComponents objectAtIndex: i];
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];
if (deleted)
{
[s appendString: @"<Delete xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
[s appendString: @"</Delete>"];
if ([syncCache objectForKey: uid])
{
[s appendString: @"<Delete xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
[s appendString: @"</Delete>"];
[syncCache removeObjectForKey: uid];
[dateCache removeObjectForKey: uid];
return_count++;
}
}
else
{
updated = YES;
if ([[component objectForKey: @"c_creationdate"] intValue] > [theSyncKey intValue])
if (![syncCache objectForKey: uid])
updated = NO;
else if ([[component objectForKey: @"c_lastmodified"] intValue] == [[syncCache objectForKey: uid] intValue])
{
DESTROY(pool);
continue;
}
return_count++;
sogoObject = [theCollection lookupName: [uid sanitizedServerIdWithType: theFolderType]
inContext: context
@ -610,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
@ -632,9 +733,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
partstat = [attendee participationStatus];
if (partstat == iCalPersonPartStatNeedsAction)
continue;
{
DESTROY(pool);
continue;
}
}
}
[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:\">"];
@ -652,13 +773,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @"</Change>"];
else
[s appendString: @"</Add>"];
}
} // for ...
folderMetadata = [NSDictionary dictionaryWithObject: [theCollection davCollectionTag]
forKey: @"SyncKey"];
return_count++;
}
DESTROY(pool);
} // for (i = 0; i < max; i++) ...
if (more_available)
{
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
[folderMetadata setObject: *theLastServerKey forKey: @"SyncKey"];
}
else
{
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
}
[self _setFolderMetadata: folderMetadata
forKey: [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]]];
RELEASE(*theLastServerKey);
}
break;
case ActiveSyncMailFolder:
@ -673,7 +809,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
int j, k, return_count;
BOOL found_in_cache;
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
max = [allMessages count];
@ -685,27 +820,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
sequence: [[[allMessages objectAtIndex: i] allValues] lastObject]]];
}
// If it's a new Sync operation, DateCache and SyncCache need to be deleted
// but GUID stored by folderSync shouldn't be touched
folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
if ([theSyncKey isEqualToString: @"-1"])
{
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"SyncCache"];
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"DateCache"];
}
// Check whether GUID in cache is equal to the GUID from imap - this is to avoid cache corruptions if a folder has been renamed and a new folder
// with the same name has been created but folderSync has not yet updated the cache
if (!([[theCollection nameInContainer] isEqualToString:
[NSString stringWithFormat: @"folder%@", [self globallyUniqueIDToIMAPFolderName: [folderMetadata objectForKey: @"GUID"] type: theFolderType]]]))
{
NSLog(@"GUID mismatch don't sync now!");
return;
}
syncCache = [folderMetadata objectForKey: @"SyncCache"];
dateCache = [folderMetadata objectForKey: @"DateCache"];
sortedBySequence = [[NSMutableArray alloc] initWithDictionary: syncCache];
[sortedBySequence sortUsingSelector: @selector(compareSequence:)];
[sortedBySequence autorelease];
@ -732,7 +846,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
found_in_cache = NO;
if (found_in_cache)
k = j+1;
else
@ -747,15 +860,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
for (; k < [allCacheObjects count]; k++)
{
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;
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? @"1" : [aCacheObject sequence]);
*theLastServerKey = [NSString stringWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
*theLastServerKey = [[NSString alloc] initWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
//NSLog(@"Reached windowSize - lastUID will be: %@", *theLastServerKey);
DESTROY(pool);
break;
}
@ -836,7 +952,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
}
DESTROY(pool);
} // for (; k < ...)
if (more_available)
{
@ -849,8 +966,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
}
[self _setFolderMetadata: folderMetadata
forKey: [theCollection nameInContainer]];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
RELEASE(*theLastServerKey);
} // default:
break;
} // switch (folderType) ...
@ -862,9 +980,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[theBuffer appendString: @"<Commands>"];
[theBuffer appendString: s];
[theBuffer appendString: @"</Commands>"];
if (more_available)
[theBuffer appendString: @"<MoreAvailable/>"];
}
}
@ -904,7 +1019,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ([[element tagName] isEqualToString: @"Add"])
{
// Add
[self processSyncAddCommand: aCommand
[self processSyncAddCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@ -913,7 +1028,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if ([[element tagName] isEqualToString: @"Change"])
{
// Change
[self processSyncChangeCommand: aCommand
[self processSyncChangeCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@ -922,15 +1037,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if ([[element tagName] isEqualToString: @"Delete"])
{
// Delete
[self processSyncDeleteCommand: aCommand
[self processSyncDeleteCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
*processed = YES;
}
else if ([[element tagName] isEqualToString: @"Fetch"])
{
// Fetch
[self processSyncFetchCommand: aCommand
[self processSyncFetchCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@ -947,14 +1063,16 @@ 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;
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *lastServerKey, *syncKeyInCache;
SOGoMicrosoftActiveSyncFolderType folderType;
id collection, value;
NSMutableString *changeBuffer, *commandsBuffer;
BOOL getChanges, first_sync;
unsigned int windowSize, v;
unsigned int windowSize, v, status;
NSMutableDictionary *folderMetadata;
changeBuffer = [NSMutableString string];
commandsBuffer = [NSMutableString string];
@ -965,6 +1083,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
collection = [self collectionFromId: realCollectionId type: folderType];
syncKey = davCollectionTag = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
if (collection == nil)
{
// Collection not found - next folderSync will do the cleanup
//NSLog(@"Sync Collection not found %@ %@", collectionId, realCollectionId);
//Outlook doesn't like following response
//[theBuffer appendString: @"<Collection>"];
//[theBuffer appendFormat: @"<SyncKey>%@</SyncKey>", syncKey];
//[theBuffer appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
//[theBuffer appendFormat: @"<Status>%d</Status>", 8];
//[theBuffer appendString: @"</Collection>"];
return;
}
// We check for a window size, default to 100 if not specfied or out of bounds
windowSize = [[[(id)[theDocumentElement getElementsByTagName: @"WindowSize"] lastObject] textValue] intValue];
@ -978,6 +1109,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
windowSize = v;
lastServerKey = nil;
status = 1;
// From the documention, if GetChanges is missing, we must assume it's a YES.
// See http://msdn.microsoft.com/en-us/library/gg675447(v=exchg.80).aspx for all details.
@ -995,6 +1127,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
first_sync = YES;
*changeDetected = YES;
}
else if ((![syncKey isEqualToString: @"-1"]) && !([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"SyncCache"]))
{
//NSLog(@"Reset folder: %@", [collection nameInContainer]);
davCollectionTag = @"0";
first_sync = YES;
*changeDetected = YES;
if (!([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"displayName"]))
status = 12; // need folderSync
else
status = 3; // do a complete resync
}
// We check our sync preferences and we stash them
bodyPreferenceType = [[(id)[[(id)[theDocumentElement getElementsByTagName: @"BodyPreference"] lastObject] getElementsByTagName: @"Type"] lastObject] textValue];
@ -1004,7 +1148,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[context setObject: bodyPreferenceType forKey: @"BodyPreferenceType"];
// We generate the commands, if any, for the response. We might also have
// generated some in processSyncCommand:inResponse: as we could have
// received a Fetch command
@ -1013,6 +1156,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]]
@ -1037,27 +1181,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inBuffer: s
processed: &processed];
if (processed)
// Windows phons don't empty Responses tags - such as: <Responses></Responses>.
// We onnly generate this tag when the command has generated a response.
if (processed && [s length])
[commandsBuffer appendFormat: @"<Responses>%@</Responses>", s];
else
[commandsBuffer appendString: s];
}
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]];
// If we got any changes or if we have applied any commands
// let's regenerate our SyncKey based on the collection tag.
if ([changeBuffer length] || [commandsBuffer length])
{
if (lastServerKey)
davCollectionTag = lastServerKey;
else if (![[self _folderMetadataForKey: [collection nameInContainer]] objectForKey: @"MoreAvailable"])
davCollectionTag = [collection davCollectionTag];
else
{
// Use the SyncKey saved by processSyncGetChanges - if processSyncGetChanges is not called (because of getChanges=false)
// SyncKey has the value of the previous sync operation.
davCollectionTag = [folderMetadata objectForKey: @"SyncKey"];
if (!davCollectionTag)
davCollectionTag = [collection davCollectionTag];
}
*changeDetected = YES;
}
else
{
if (folderType == ActiveSyncMailFolder && [syncKey isEqualToString: @"-1"])
davCollectionTag = [collection davCollectionTag];
// Make sure that client is updated with the right syncKey. - This keeps vtodo's and vevent's syncKey in sync.
syncKeyInCache = [folderMetadata objectForKey: @"SyncKey"];
if (syncKeyInCache && !([davCollectionTag isEqualToString:syncKeyInCache]))
{
davCollectionTag = syncKeyInCache;
*changeDetected = YES;
}
}
// Generate the response buffer
@ -1074,10 +1232,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[theBuffer appendFormat: @"<SyncKey>%@</SyncKey>", davCollectionTag];
[theBuffer appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
[theBuffer appendFormat: @"<Status>%d</Status>", status];
// MoreAvailable breaks Windows Mobile devices if not between <Status> and <Commands>
// https://social.msdn.microsoft.com/Forums/en-US/040b254e-f47e-4cc1-a397-6d8393cdb819/airsyncmoreavailable-breaks-windows-mobile-devices-what-am-i-doing-wrong?forum=os_exchangeprotocols
if ([folderMetadata objectForKey: @"MoreAvailable"])
[theBuffer appendString: @"<MoreAvailable/>"];
[theBuffer appendString: changeBuffer];
[theBuffer appendString: commandsBuffer];
[theBuffer appendString: changeBuffer];
[theBuffer appendString: @"</Collection>"];
}
@ -1186,21 +1349,42 @@ 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 string];
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];
defaultInterval = [defaults maximumSyncInterval];
internalInterval = [defaults internalSyncInterval];
// If the request doesn't contain "HeartbeatInterval" there is no reason to delay the response.
if (heartbeatInterval == 0)
heartbeatInterval = internalInterval = 1;
// We check to see if our heartbeat interval falls into the supported ranges.
if (heartbeatInterval > defaultInterval || heartbeatInterval < 1)
{
@ -1217,7 +1401,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 < (defaultInterval/internalInterval); i++)
for (i = 0; i < (heartbeatInterval/internalInterval); i++)
{
s = [NSMutableString string];
@ -1225,31 +1409,46 @@ 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)
{
NSLog(@"Change detected, we push the content.");
[self logWithFormat: @"Change detected, we push the content."];
break;
}
else if (heartbeatInterval > 1)
{
[self logWithFormat: @"Sleeping %d seconds while detecting changes...", internalInterval];
sleep(internalInterval);
}
else
{
NSLog(@"Sleeping %d seconds while detecting changes...", internalInterval);
sleep(internalInterval);
break;
}
}
// 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>"];
d = [[output dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
[output appendString: @"</Collections></Sync>"];
[theResponse setContent: d];
d = [output dataUsingEncoding: NSUTF8StringEncoding];
d = [d xml2wbxml];
[theResponse setContent: d];
}
// Avoid overloading the autorelease pool here, as Sync command can
// generate fairly large responses.
RELEASE(output);
}
@end

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SOGoMailObject+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
@ -67,8 +66,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Appointments/iCalPerson+SOGo.h>
#include <Mailer/NSString+Mail.h>
#include <Mailer/SOGoMailBodyPart.h>
#include <SOGo/SOGoUser.h>
#include <SOGo/NSString+Utilities.h>
typedef struct {
uint32_t dwLowDateTime;
@ -283,7 +282,7 @@ struct GlobalObjectId {
performed: b];
}
}
else if ([thePart isKindOfClass: [NGMimeBodyPart class]])
else if ([thePart isKindOfClass: [NGMimeBodyPart class]] || [thePart isKindOfClass: [NGMimeMessage class]])
{
NGMimeFileData *fdata;
id body;
@ -323,6 +322,11 @@ struct GlobalObjectId {
if (s)
{
// We sanitize the content immediately, in case we have non-UNICODE safe
// characters that would be re-encoded later in HTML entities and thus,
// ignore afterwards.
s = [s safeString];
body = [s dataUsingEncoding: NSUTF8StringEncoding];
}
@ -362,8 +366,7 @@ struct GlobalObjectId {
if (message)
{
[self _sanitizedMIMEPart: [message body]
performed: &b];
[self _sanitizedMIMEPart: message performed: &b];
if (b)
{
@ -506,7 +509,6 @@ struct GlobalObjectId {
//
- (NSString *) activeSyncRepresentationInContext: (WOContext *) _context
{
NSAutoreleasePool *pool;
NSData *d, *globalObjId;
NSArray *attachmentKeys;
NSMutableString *s;
@ -699,10 +701,6 @@ struct GlobalObjectId {
// Body - namespace 17
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
// Make use of a local pool here as _preferredBodyDataUsingType:nativeType: will consume
// a significant amout of RAM and file descriptors
pool = [[NSAutoreleasePool alloc] init];
nativeBodyType = 1;
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
@ -742,9 +740,7 @@ struct GlobalObjectId {
}
[s appendString: @"</Body>"];
}
DESTROY(pool);
// Attachments -namespace 16
attachmentKeys = [self fetchFileAttachmentKeys];
if ([attachmentKeys count])

View File

@ -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

View File

@ -61,7 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[response setHeader: @"private" forKey: @"Cache-Control"];
[response setHeader: @"OPTIONS, POST" forKey: @"Allow"];
[response setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
[response setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
[response setHeader: @"2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
[response setHeader: @"OPTIONS, POST" forKey: @"Public"];
}

View File

@ -16,10 +16,11 @@ ADDITIONAL_INCLUDE_DIRS += \
-I../../SOPE
ADDITIONAL_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/ \
-L../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo \
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
-L/usr/local/lib
-L/usr/local/lib \
-Wl,-rpath,$(SOGO_SYSLIBDIR)/sogo
BUNDLE_LIBS += \
-lSOGo \

View File

@ -76,13 +76,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
NSArray *attendees;
NSArray *attendees, *categories;
iCalPerson *organizer, *attendee;
iCalTimeZone *tz;
id o;
int v;
int v, i, meetingStatus;
NSTimeZone *userTimeZone;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
@ -127,13 +127,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
if (!tz)
tz = [iCalTimeZone timeZoneForName: @"Europe/London"];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
// Organizer and other invitations related properties
if ((organizer = [self organizer]))
{
meetingStatus = 1; // meeting and the user is the meeting organizer.
o = [organizer rfc822Email];
if ([o length])
{
@ -159,7 +160,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @"<Attendee xmlns=\"Calendar:\">"];
attendee = [attendees objectAtIndex: i];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [attendee rfc822Email]];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
attendee_status = [self _attendeeStatus: attendee];
@ -177,6 +178,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
[s appendString: @"</Attendees>"];
}
else
{
meetingStatus = 0; // appointment
}
// This depends on the 'NEEDS-ACTION' parameter.
// This will trigger the SendMail command
@ -186,18 +191,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
int attendee_status;
meetingStatus = 3; // event is a meeting, and the user is not the meeting organizer
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];
}
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", meetingStatus];
// Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx
if ([[self summary] length])
[s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
@ -223,12 +231,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Sensitivity
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
v = 3;
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
categories = [self categories];
if ([categories count])
{
[s appendFormat: @"<Categories xmlns=\"Calendar:\">"];
for (i = 0; i < [categories count]; i++)
{
[s appendFormat: @"<Category xmlns=\"Calendar:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
// TODO: improve this to handle more alarm types
@ -250,11 +271,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
o = [self comment];
if ([o length])
{
// 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>"];
}
@ -310,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"]))
@ -334,18 +355,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[o intValue];
}
//
//
//
if ((o = [theValues objectForKey: @"MeetingStatus"]))
{
[o intValue];
}
//
// 0- normal, 1- personal, 2- private and 3-confidential
//
if ((o = [theValues objectForKey: @"Sensitivy"]))
if ((o = [theValues objectForKey: @"Sensitivity"]))
{
switch ([o intValue])
{
@ -362,9 +375,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
if ((o = [theValues objectForKey: @"TimeZone"]))
// Categories
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
[self setCategories: o];
// We ignore TimeZone sent by mobile devices for now.
// Some Windows devices don't send during event updates.
//if ((o = [theValues objectForKey: @"TimeZone"]))
// {
// }
//else
{
// Ugh, we ignore it for now.
// 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];
@ -383,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];
}
}
@ -410,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];
}
}
@ -481,11 +488,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setOrganizer: person];
}
//
// iOS is plain stupid here. It seends event invitations with no Organizer.
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
// and there's no organizer, we fake one.
//
if ((o = [theValues objectForKey: @"MeetingStatus"]))
{
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"])
{
iCalPerson *person;
person = [iCalPerson elementWithTag: @"organizer"];
[person setEmail: [[[context activeUser] primaryIdentity] objectForKey: @"email"]];
[person setCn: [[context activeUser] cn]];
[person setPartStat: @"ACCEPTED"];
[self setOrganizer: person];
}
}
// 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.
if (![self userIsAttendee: [context activeUser]])
{
if ((o = [theValues objectForKey: @"Attendees"]))
// Windows phones sens sometimes an empty Attendees tag.
// We check it's an array before processing it.
if ((o = [theValues objectForKey: @"Attendees"])&& [o isKindOfClass: [NSArray class]])
{
NSMutableArray *attendees;
NSDictionary *attendee;

View File

@ -76,15 +76,17 @@ struct SYSTEMTIME {
byMonth = [rrule byMonth];
if ([byMonth count] > 0)
{
tzData->wYear = 0;
tzData->wMonth = [[byMonth objectAtIndex: 0] intValue];
mask = [rrule byDayMask];
tzData->wDayOfWeek = [mask firstDay];
tzData->wDay = [mask firstOccurrence];
tzData->wDay = ([mask firstOccurrence] == -1) ? 5 : [mask firstOccurrence];
dateValue = [self startDate];
tzData->wHour = [dateValue hourOfDay];
tzData->wMinute = [dateValue minuteOfHour];
tzData->wSecond = [dateValue secondOfMinute];
tzData->wMilliseconds = 0;
}
}

View File

@ -54,9 +54,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
NSArray *categories;
id o;
int v;
int v, i;
s = [NSMutableString string];
@ -96,9 +97,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Reminder - FIXME
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
// Sensitivity - FIXME
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", 0];
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
v = 3;
else
v = 0;
categories = [self categories];
if ([categories count])
{
[s appendFormat: @"<Categories xmlns=\"Tasks:\">"];
for (i = 0; i < [categories count]; i++)
{
[s appendFormat: @"<Category xmlns=\"Tasks:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
// Subject
o = [self summary];
if ([o length])
@ -106,11 +123,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [self comment]))
{
// 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>"];
}
@ -125,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];
@ -147,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"];
}
@ -159,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];
}
@ -182,6 +188,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setPriority: @"9"];
}
//
// 0- normal, 1- personal, 2- private and 3-confidential
//
if ((o = [theValues objectForKey: @"Sensitivity"]))
{
switch ([o intValue])
{
case 2:
[self setAccessClass: @"PRIVATE"];
break;
case 3:
[self setAccessClass: @"CONFIDENTIAL"];
break;
case 0:
case 1:
default:
[self setAccessClass: @"PUBLIC"];
}
}
// Categories
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
[self setCategories: o];
if ((o = [theValues objectForKey: @"ReminderTime"]))
{

View File

@ -26,12 +26,23 @@ Alias /SOGo/WebServerResources/ \
## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
## below.
#
## For full proxy-side authentication:
#<Location /SOGo>
# AuthType XXX
# Require valid-user
# SetEnv proxy-nokeepalive 1
# Allow from all
#</Location>
#
## For proxy-side authentication only for CardDAV and GroupDAV from external
## clients:
#<Location /SOGo/dav>
# AuthType XXX
# Require valid-user
# SetEnv proxy-nokeepalive 1
# Allow from all
#</Location>
ProxyRequests Off
SetEnv proxy-nokeepalive 1
@ -64,7 +75,8 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
## When using proxy-side autentication, you need to uncomment and
## adjust the following line:
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e"
RequestHeader unset "x-webobjects-remote-user"
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"

2960
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
all: $(patsubst %.asciidoc,%.pdf,$(wildcard *.asciidoc))
%.pdf : %.asciidoc
asciidoc -a docinfo1 -b docbook -d book -d book -o $<.docbook $<
asciidoc -a docinfo1 -b docbook -d book -o $<.docbook $<
fop -c fonts/fop-config.xml -xsl docbook/xsl/sogo-fo.xsl -xml $<.docbook -pdf $@
clean:

View File

@ -80,6 +80,12 @@ and others) 
* SMTP server (Postfix, Sendmail and others)
* IMAP server (Courier, Cyrus IMAP Server, Dovecot and others)
If you plan to use ActiveSync, an IMAP server supporting the ACL,
UIDPLUS, QRESYNC, ANNOTATE (or X-GUID) IMAP extensions is required,
such as Cyrus IMAP version 2.4 or later, or Dovecot version
2.1 or later. If your current IMAP server does not support these
extensions, you can use Dovecot's proxying capabilities.
In this guide, we assume that all those components are running on the
same server (i.e., `localhost` or `127.0.0.1`) that SOGo will be
installed on.
@ -193,7 +199,7 @@ installation for a Red Hat or CentOS distribution.
Software Downloads
~~~~~~~~~~~~~~~~~~
SOGo can be installed using the+yum+utility. To do so, first create
SOGo can be installed using the `yum` utility. To do so, first create
the `/etc/yum.repos.d/inverse.repo` configuration file with the following
content:
@ -258,13 +264,13 @@ In SOGo, the user's applications settings are stored
in `/etc/sogo/sogo.conf`. You can use your favourite text editor to
modify the file.
The +sogo.conf+ file is a serialized _property list_. This simple format
The `sogo.conf` file is a serialized _property list_. This simple format
encapsulates four basic data types: arrays, dictionaries (or hashes),
strings and numbers. Numbers are represented as-is, except for booleans
which can take the unquoted values `YES` and `NO`. Strings are not
mandatorily quoted, but doing so will avoid you many problems. A
dictionary is a sequence of key and value pairs separated in their
middle with a `=` sign. It starts with a `\{` and ends with a
middle with a `=` sign. It starts with a `{` and ends with a
corresponding `}`. Each value definition in a dictionary ends with a
semicolon. An array is a chain of values starting with `(` and ending
with `)`, where the values are separated with a `,`. Also, the file
@ -273,6 +279,11 @@ is not required, only recommended. Block comments are delimited by `/*`
and `*/` and can span multiple lines while line comments must start with
`//`.
The configuration must be contained in a root dictionary, thus be completely
wrapped within curly brackets `{ [configuration] }`. If SOGo refuses to
start due to syntax errors in its configuration file, `plparse` is helpful
for finding these, as it indicates the line containing the problem.
Preferences Hierarchy
~~~~~~~~~~~~~~~~~~~~~
@ -425,29 +436,42 @@ Defaults to `YES` when unset.
|The location of the SSL private key file on the filesystem that is used
by SOGo to sign and encrypt communications with the SAML2 identity
provider. This file must be generated for each running SOGo service
(rather than host).
(rather than host). Make sure this file is readable by the SOGo user.
|S |SOGoSAML2CertiticateLocation
|The location of the SSL certificate file. This file must be generated
for each running SOGo service.
for each running SOGo service. Make sure this file is readable by the SOGo user.
|S |SOGoSAML2IdpMetadataLocation
|The location of the metadata file that describes the services available
on the SAML2 identify provider.
on the SAML2 identify provider. The content of this file is usually generated
directly by your SAML 2.0 IdP solution. For example, using SimpleSAMLphp, you
can get the metadata directly from https://MYSERVER/simplesaml/saml2/idp/metadata.php
Make sure this file is readable by the SOGo user.
|S |SOGoSAML2IdpPublicKeyLocation
|The location of the SSL public key file on the filesystem that is used
by SOGo to sign and encrypt communications with the SAML2 identity
provider. This file should be part of the setup of your identity
provider.
provider. Make sure this file is readable by the SOGo user.
|S |SOGoSAML2IdpCertificateLocation
|The location of the SSL certificate file. This file should be part of
the setup of your identity provider.
the setup of your identity provider. Make sure this file is readable by the SOGo user.
|S |SOGoSAML2LoginAttribute
|The attribute provided by the IdP to identify the user in SOGo.
|S |SOGoSAML2LogoutEnabled
|Boolean value indicated whether the "Logout" link is enabled when using
SAML2 as authentication mechanism.
SAML2 as authentication mechanism. When using this feature, SOGo will invoke
the IdP to proceed with the logout procedure. When the user clicks on the logout
button, a redirection will be made to the IdP to trigger the logout.
|S |SOGoSAML2LogoutURL
|The URL to which redirect the user after the "Logout" link is clicked.
SOGoSAML2LogoutEnabled must be set to YES. If unset, the user will be
redirected to a blank page.
|D |SOGoTimeZone
|Parameter used to set a default time zone for users. The default
@ -887,7 +911,8 @@ resource if the entry has the calendarresource objectClass set.
to which a resource can be part of at any point in time.
If this is set to `0`, or if the attribute is missing, it means no
limit.
limit. If set to `-1`, no limit is imposed but the resource will
be marked as busy the first time it is booked.
|filter (optional)
|The filter to use for LDAP queries, it should be defined as an
@ -974,7 +999,9 @@ context as Dovecot stores in its database.
|passwordPolicy
|If set to `YES`, SOGo will use the extended LDAP Password Policies
attributes. If you LDAP server does not support those and you activate
this feature, every LDAP requests will fail.
this feature, every LDAP requests will fail. Note that some LDAP servers
require LDAP/SSL for password policies to work. This is the case for
example with 389 Directory Server.
|isAddressBook
|If set to `YES`, this LDAP source is used as a shared address book
@ -1167,7 +1194,7 @@ keytool -import -keystore /etc/ssl/certs/java/cacerts \
*The certificate used by the CAS server must also be trusted by SOGo.*
In case of a self-signed certificate, this means exporting tomcat's
certificate using the +keytool+utility, converting it to PEM format and
certificate using the `keytool` utility, converting it to PEM format and
appending it to the `ca-certificates.crt` file (the name and location of
that file differs between distributions). Basically:
@ -1230,13 +1257,32 @@ documentation of your identity provider and the SAML2 configuration keys
that are listed above for proper setup. Once a SOGo instance is
configured properly, the metadata for that instance can be retrieved
from `http://<hostname>/SOGo/saml2-metadata` for registration with the
identity provider.
identity provider. SOGo will dynamically generate the metadata based on
the SOGoSAML2CertificateLocation's content and the SOGo server name.
When using SimpleSAMLphp, make sure the convert OID to names by modifying your
`metadata/saml20-idp-hosted.php` to contain something like this:
----
'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
'authproc' => array(
100 => array('class' => 'core:AttributeMap', 'oid2name'),
),
----
If you want to test the IdP-initiated logout using SimpleSAMLphp, you can do so by opening
the following URL:
----
https://idp.example.org/simplesaml/saml2/idp/SingleLogoutService.php?ReturnTo=www.sogo.nu
----
In order to relay authentication information to your IMAP server and if
you make use of the CrudeSAML SASL plugin, you need to make sure that
_NGImap4AuthMechanism_ is configured to use the `SAML` mechanism. If you
make use of the CrudeSAML PAM plugin, this value may be left empty.
Database Configuration
~~~~~~~~~~~~~~~~~~~~~~
@ -1433,7 +1479,10 @@ case, SOGo will consider the returned entry to be a resource.
which a resource can be part of at any point in time.
If this is set to `0`, or if the attribute is missing, it means no
limit.
limit and the resource will always be marked as free. If set to `-1`,
no limit is imposed but the resource will be marked as busy the first
time it is booked. If greater than 0, the resource will get marked as
busy once it reaches the value.
|DomainFieldName (optional)
|If set, SOGo will use the value of that field as the domain associated
@ -1581,8 +1630,8 @@ Note that TLS is supported but SSL is not.
|D |SOGoSieveFolderEncoding
|Parameter used to specify which encoding is used for IMAP folder names
in Sieve filters. Defaults to "UTF-7". The other possible value is
"UTF-8".
in Sieve filters. Defaults to `UTF-7`. The other possible value is
`UTF-8`.
|U |SOGoMailShowSubscribedFoldersOnly
|Parameter used to specify if the Web interface should only show
@ -1632,6 +1681,12 @@ cronjob `sogo-tmpwatch`.
Defaults to `/var/spool/sogo`.
|S |NGImap4DisableIMAP4Pooling
|Disables IMAP pooling when set to `YES`. Enable pooling by setting to
`NO` or using a caching proxy like imapproxy.
The default value is `YES`.
|S |NGImap4ConnectionStringSeparator
|Parameter used to set the IMAP mailbox separator. Setting this will
also have an impact on the mailbox separator used by Sieve filters.
@ -1644,7 +1699,7 @@ SASL mechanism. Please note that feature might be limited at this time.
|D |NGImap4ConnectionGroupIdPrefix
|Prefix to prepend to names in IMAP ACL transactions, to indicate the
name is a group name not a user name.
name is a group name, not a user name.
RFC4314 gives examples where group names are prefixed with `$`. Dovecot,
for one, follows this scheme, and will, for example, apply permissions
@ -1993,7 +2048,7 @@ Defaults to `NO` when unset.
SOGo Configuration Summary
~~~~~~~~~~~~~~~~~~~~~~~~~~
The complete SOGo configuration file+/etc/sogo/sogo.conf+should look
The complete SOGo configuration file `/etc/sogo/sogo.conf` should look
like this:
----
@ -2325,7 +2380,7 @@ ActiveSync:
|Parameter used to set the maximum amount of time, in seconds, SOGo will
wait before replying to a Ping command.
If not set, it defaults to `5` seconds.
If not set, it defaults to `10` seconds.
|S |SOGoMaximumSyncInterval
|Parameter used to set the maximum amount of time, in seconds, SOGo will
@ -2336,10 +2391,20 @@ If not set, it defaults to `30` seconds.
|S |SOGoInternalSyncInterval
|Parameter used to set the maximum amount of time, in seconds, SOGo will
wait before doing an internal check for data changes (add, delete, and
update). This parameter must be lower than _SOGoMaximumSyncInterval_.
update). This parameter must be lower than _SOGoMaximumSyncInterval_ and
_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.
@ -2352,24 +2417,18 @@ have unexpected behaviour with various ActiveSync clients.
Please be aware of the following limitations:
* Currently, only the personal calendar and address book are
synchronized. Adding support for all folders is planned.
* When creating an Outlook 2013 profile, you must actually kill Outlook
before the end of the creation process. See http://www.vionblog.com/connect-zimbra-community-with-outlook-2013
for a procedure example.
* Outlook 2013 does not search the GAL. One possible alternative
solution is to configure Outlook to use a LDAP server (over SSL) with
authentication. Alternatively, when supporting more than just the
personal address book, we'll also be able to expose the LDAP/SQL based
address books in SOGo over ActiveSync.
authentication. Outlook 2013 also does not seem to support multiple
address books over ActiveSync.
* Make sure you do not use a self-signed certificate. While this will
work, Outlook will work intermittently as it will raise popups for
certificate validation, sometimes in background, preventing the user to
see the warning and thus, preventing any synchronization to happen.
* ActiveSync clients keep connections open for a while. Each connection
will grab a hold on a sogod process so you will need a lot of processes
to handle many clients. This limitation will eventually be overcome in
SOGo.
to handle many clients. Make sure you tune your SOGo server when having
lots of ActiveSync clients.
* Repetitive events with occurrences exceptions are currently not
supported.
* Outlook 2013 Autodiscovery is currently not supported.
@ -2379,6 +2438,10 @@ see http://support.microsoft.com/kb/291621 for configuration
instructions. On the SOGo side, _SOGoEnablePublicAccess_ must be set to
`YES` and the URL to use must be of the following format:
`http://<hostname>/SOGo/dav/public/%NAME%/freebusy.ifb`
* If you have very large mail folders (thousands of messages), you will
need to adjust the word size of your IMAP server. In Dovecot, the parameter
to increase is "imap_max_line_length" while under Cyrus IMAP Server, the
parameter is "maxword". We suggest a buffer of 2MB.
In order to use the SOGo ActiveSync support code in production
environments, you need to get a proper usage license from Microsoft.
@ -2387,7 +2450,7 @@ user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
http://www.microsoft.com/en-us/legal/intellectualproperty/
 
and send an email to iplicreq@microsoft.com
@ -2513,7 +2576,7 @@ any mobile devices that support Microsoft ActiveSync. Microsoft Outlook
2013 is also supported.
The Microsoft ActiveSync server URL is generally something
like: `http://localhost/Microsoft-Active-Sync`.
like: `http://localhost/Microsoft-Server-ActiveSync`.
Upgrading
---------

View File

@ -233,13 +233,12 @@ Installation
This section will guide you through the installation of the native
Microsoft Outlook compatibility layer SOGo offers.
Red Hat Enterprise Linux v5 and v6
Red Hat Enterprise Linux v6 x86_64
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are using Red Hat Enterprise Linux (or CentOS) version 5 or
version 6, packages for Samba 4, OpenChange and SOGo and the SOGo
OpenChange backend are available from SOGo's web site. Please follow the
instructions from
If you are using Red Hat Enterprise Linux version 6 x86_64, packages
for Samba 4, OpenChange and SOGo and the SOGo OpenChange backend are
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend_nightly.html.
In order to satisfy certain dependencies, you should also add the EPEL
@ -253,53 +252,48 @@ installation:
----
yum clean all && yum makecache
yum install samba4 \
yum install samba \
openchange \
sogo-openchange-backend \
openchange-ocsmanager \
openchange-rpcproxy
openchange-rpcproxy \
mysql-server \
MySQL-python
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
Debian 6.0 (Squeeze) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[NOTE]
Samba4/OpenChange are not available for now on CentOS 5 i386/x86_64,
CentOS 6 i386 and CentOS 7.
Samba 4, OpenChange, SOGo and the SOGo OpenChange backend are now
Debian 7.0 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOGo, OpenChange and the SOGo OpenChange backend are now
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend_nightly.html to setup your
http://www.sogo.nu/english/downloads/backend.html to setup your
apt sources.
Debian Squeeze ships an older version of some libraries required by
Samba 4. In order to workaround this, users of this distribution will
have to use the _squeeze-backports_ repository. To do so, create
For Samba 4, you need to use the _wheezy-backports_ repository. To do so, create
`/etc/apt/sources.list.d/backports.list`:
deb http://backports.debian.org/debian-backports squeeze-backports main
deb http://http.debian.net/debian wheezy-backports main
Then install the dependencies on Debian Squeeze, do:
On Ubuntu 12.04, you will also have to add the Wheezy sources:
----
apt-get update
apt-get install -t squeeze-backports libwbclient-dev samba-common smbclient libsmbclient libsmbclient-dev
----
deb http://ftp.us.debian.org/debian wheezy main
deb http://security.debian.org/ wheezy/updates main
Once ready, install the `samba4` package on top of an existing SOGo
Then install Samba 4 on top of an existing SOGo
installation:
----
apt-get update
apt-get install samba4
apt-get -t wheezy-backports install samba samba-dev
----
The current post installation script shipped with the Samba 4 package is
far from perfect and might fail even on a fresh install. The following
command is needed to let dpkg know that everything is fine about Samba 4
if the post install script fails.
sed --in-place 'N; s/Package: samba4\nStatus: install ok half-configured/Package: samba4\nStatus: install ok installed/;' /var/lib/dpkg/status
Once completed, install the packages related to OpenChange and the SOGo
provider:
@ -307,13 +301,53 @@ provider:
apt-get install openchangeserver \
sogo-openchange \
openchangeproxy \
openchange-ocsmanager \
openchange-rpcproxy
python-ocsmanager \
mysql-server \
python-mysqldb
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
[NOTE]
On Ubuntu 12.04, the Samba init scripts need to be modified to
disable the upstart check. For more details, refer to:
https://wiki.samba.org/index.php/Samba4/InitScript
Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~
For Ubuntu 14.04, you must not use the Debian Wheezy backports.
Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html to setup your
apt sources.
Then install Samba 4 on top of an existing SOGo
installation:
----
apt-get update
apt-get install samba samba-dev
----
Once completed, install the packages related to OpenChange and the SOGo
provider:
----
apt-get install openchangeserver \
sogo-openchange \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
Configuration
-------------
@ -349,16 +383,14 @@ You might consider changing the realm and domain used, to suit your
enviroment.
You might also have to
remove `/etc/samba4/smb.conf` (or `/etc/samba/smb.conf` on Debian-based
distributions) prior running this command.
remove `/etc/samba/smb.conf` prior running this command.
Add the following parameters to the `[global]` section of the
`/etc/samba4/smb.conf` (`/samba/smb.conf` if you use a Debian-based
distribution) configuration file:
`/etc/samba/smb.conf` configuration file:
----
### Configuration required by OpenChange server ###
dcerpc endpoint servers = +epmapper, +mapiproxy
dcerpc endpoint servers = epmapper, mapiproxy, dnsserver
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
### Configuration required by OpenChange server ###
@ -392,11 +424,22 @@ Your Samba 4 configuration file should look like this:
OpenChange Configuration
~~~~~~~~~~~~~~~~~~~~~~~~
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
First, create the OpenChange MySQL user:
----
$ mysql -u root -p
mysql> CREATE USER 'openchange-user'@'localhost' IDENTIFIED BY 'openchange$123';
mysql> GRANT ALL PRIVILEGES ON `openchange`.* TO 'openchange-user'@'localhost' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
----
The Samba AD schema needs to be filled with additional object
definitions by running the following commands: 
----
openchange_provision
openchange_provision --standalone
NOTE: This operation can take several minutes
[+] Step 1: Register Exchange OIDs
@ -410,38 +453,59 @@ NOTE: This operation can take several minutes
[+] Step 9: Add Exchange classes to Samba schema
[+] Step 10: Add possSuperior attributes to Exchange classes
[+] Step 11: Extend existing Samba classes and attributes
[+] Step 12: Exchange Samba with Exchange configuration objects
[+] Step 12: Generic Exchange configuration objects
[+] Step 13: Finalize generic Exchange configuration objects
[SUCCESS] Done!
[+] Step 1: Exchange Samba registration
[SUCCESS] Done!
[+] Step 1: Register Exchange Samba as the main server
[SUCCESS] Done!
----
You can safely ignore the "`ERROR: no subClassOf 'serviceAdministrationPoint' for 'rRASAdministrationConnectionPoint'`" message when running the `openchange_provision` command.
Provision the OpenChange database: 
Create the OpenChange database: 
----
openchange_provision --openchangedb
openchange_provision --openchangedb --openchangedb-uri 'mysql://openchange-user:openchange$123@localhost/openchange'
Setting up openchange db
[+] Public Folders
===================
* Public Folder Root 0x0100000000000001
* IPM_SUBTREE 0x0200000000000001
* NON_IPM_SUBTREE 0x0300000000000001
* EFORMS REGISTRY 0x0400000000000001
* OFFLINE ADDRESS BOOK 0x0500000000000001
* /o=First Organization/cn=addrlists/cn=oabs/cn=Default Offline Address Book 0x0600000000000001
* SCHEDULE+ FREE BUSY 0x0700000000000001
* EX:/o=First Organization/ou=Exchange Administrative Group (UBUNTU-OC) 0x0800000000000001
* Events Root 0x0900000000000001
* Public Folder Root : 0x0100000000000001 (72057594037927937)
* IPM_SUBTREE : 0x0200000000000001 (144115188075855873)
* NON_IPM_SUBTREE : 0x0300000000000001 (216172782113783809)
* EFORMS REGISTRY : 0x0400000000000001 (288230376151711745)
* OFFLINE ADDRESS BOOK : 0x0500000000000001 (360287970189639681)
* /o=First Organization/cn=addrlists/cn=oabs/cn=Default Offline Address Book: 0x0600000000000001 (432345564227567617)
* SCHEDULE+ FREE BUSY : 0x0700000000000001 (504403158265495553)
* EX:/o=first organization/ou=first administrative group: 0x0800000000000001 (576460752303423489)
* Events Root : 0x0900000000000001 (648518346341351425)
----
Finally, modify `/etc/samba/smb.conf` to specify OpenChange connection information
for its indexing database. Add the following at the end of the `[global]` section:
----
mapistore:namedproperties = mysql
namedproperties:mysql_user = openchange-user
namedproperties:mysql_pass = openchange$123
namedproperties:mysql_host = localhost
namedproperties:mysql_db = openchange
mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/openchange
mapiproxy:openchangedb = mysql://openchange-user:openchange$123@localhost/openchange
----
On RHEL, make sure SELinux is disabled:
setenforce 0
Next, you can start Samba using the usual command :
Next, you can start Samba using the usual command:
/etc/init.d/samba4 start
/etc/init.d/samba start
On upstart-based distributions, use:
start samba-ad-dc
You can also launch the OpenChange web services:
@ -503,6 +567,10 @@ On Debian-based distributions, do:
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
[NOTE]
Debian-based distributions are not supported anymore for
OCSManager/rpcproxy. Support will soon resume.
Name Service Configuration for Web Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -540,14 +608,13 @@ samba-tool domain passwordsettings set --complexity=off
samba-tool domain passwordsettings set --min-pwd-length=1
samba-tool user add <username>
samba-tool user setexpiry <username> --noexpiry
# create user in openchange+ +openchange_newuser --create <username>
# create user in openchange
openchange_newuser --create <username>
----
If you don't have a trust between your IMAP server and SOGo, you must at
this point set the cleartext password of the newly created user in
`/var/lib/samba4/private/mapistore/<username/password` (or
`/var/lib/samba/private/mapistore/<username/password` on Debian-based
distributions).
`/var/lib/samba/private/mapistore/<username/password`.
This per-user file contains the cleartext password of the user as a
UTF-8 string, on a single line. This password will be used to

View File

@ -1,193 +0,0 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<!-- ********************************************************************
SOGo Documentation Docbook FO Parameters
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
Copyright (C) 2011-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
******************************************************************** -->
<!--
Global Tasks
TODO prettier revhistory
TODO prettier Table of Contents
TODO generate PDF table of contents (like OSX's Preview shows on the right hand side)
TODO title 2
- align with text?
- more above whitespace
TODO change the bullet for a prettier one
TODO title 3 and 4
- align with text?
- should be easier to differentiate (check network guide)
TODO icon on line wrap in monospace boxes
TODO caution, notes, warnings, etc.
- box around it
- sexy icon
TODO -> is converted into an arrow but it's not pretty (is it font or docbook-thingy?)
-->
<!--
Load default values
Real upstream schema is at:
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
but we decided to load all sensible local xsd since it only produce a warning on missing imports.
-->
<!-- CentOS / RHEL -->
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
<!-- Debian / Ubuntu -->
<xsl:import href="/usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl"/>
<!-- OSX through mac ports -->
<xsl:import href="/opt/local/share/xsl/docbook-xsl/fo/docbook.xsl"/>
<!-- title page extra styling -->
<xsl:import href="titlepage-fo.xsl"/>
<!-- header / footer extra styling -->
<xsl:import href="headerfooter-fo.xsl"/>
<!-- attaching an image to the verso legalnotice component -->
<xsl:template match="legalnotice" mode="book.titlepage.verso.mode">
<xsl:apply-templates mode="titlepage.mode"/>
<fo:block text-align="right">
<fo:external-graphic src="url('images/inverse-logo.jpg')" width="3in" content-width="scale-to-fit"/>
</fo:block>
</xsl:template>
<!-- stylesheet options -->
<xsl:param name="title.font.family">Lato-Medium</xsl:param>
<xsl:param name="chapter.autolabel" select="0"/>
<xsl:attribute-set name="component.title.properties">
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
<xsl:attribute name="border-bottom">solid 2px</xsl:attribute>
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="section.title.level1.properties">
<xsl:attribute name="border-bottom">solid 1px</xsl:attribute>
<xsl:attribute name="margin-top">1em</xsl:attribute>
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="section.title.level2.properties">
<xsl:attribute name="margin-top">1em</xsl:attribute>
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="section.title.level3.properties">
<xsl:attribute name="margin-top">1em</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="section.title.level4.properties">
<xsl:attribute name="margin-top">1em</xsl:attribute>
</xsl:attribute-set>
<!-- paragraph spacing -->
<xsl:attribute-set name="normal.para.spacing">
<xsl:attribute name="space-before.optimum">1.5em</xsl:attribute>
<xsl:attribute name="space-before.minimum">1.5em</xsl:attribute>
<xsl:attribute name="space-before.maximum">2.2em</xsl:attribute>
</xsl:attribute-set>
<!-- default fonts -->
<xsl:param name="body.font.family">Lato-Light</xsl:param>
<xsl:param name="body.font.master">10</xsl:param>
<xsl:param name="monospace.font.family">Incosolata</xsl:param>
<!-- revision table layout -->
<xsl:attribute-set name="revhistory.title.properties">
<xsl:attribute name="font-size">12pt</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="text-align">center</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="revhistory.table.properties">
<xsl:attribute name="break-before">page</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="revhistory.table.cell.properties">
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
</xsl:attribute-set>
<!-- Table Of Contents (TOC) options -->
<!-- We only want 2 level of ToC depth -->
<xsl:param name="toc.section.depth" select="2"/>
<!-- titles left margin -->
<xsl:attribute-set name="section.title.properties">
<xsl:attribute name="start-indent"><xsl:value-of select="$body.start.indent"/></xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="list.item.spacing">
<xsl:attribute name="space-before.optimum">0em</xsl:attribute>
<xsl:attribute name="space-before.minimum">0em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.2em</xsl:attribute>
</xsl:attribute-set>
<!-- lists type -->
<xsl:template name="itemizedlist.label.markup">
<xsl:param name="itemsymbol" select="'square'"/>
<xsl:choose>
<xsl:when test="$itemsymbol='square'"><fo:inline font-family="Lato">&#x220f;</fo:inline></xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="next.itemsymbol">
<xsl:param name="itemsymbol" select="'default'"/>
<xsl:choose>
<xsl:otherwise>square</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- admonition -->
<xsl:param name="admon.graphics" select="1"></xsl:param>
<xsl:param name="admon.graphics.path">images/</xsl:param>
<xsl:param name="admon.graphics.extension">.png</xsl:param>
<xsl:attribute-set name="graphical.admonition.properties">
<xsl:attribute name="border-top">1px solid</xsl:attribute>
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
<xsl:attribute name="margin-left">2em</xsl:attribute>
</xsl:attribute-set>
<!-- grey boxes around code (screen, programlisting) -->
<xsl:param name="shade.verbatim" select="1"/>
<xsl:attribute-set name="shade.verbatim.style">
<xsl:attribute name="background-color">#E0E0E0</xsl:attribute>
<xsl:attribute name="border">thin #9F9F9F solid</xsl:attribute>
<xsl:attribute name="margin">0pt</xsl:attribute>
<xsl:attribute name="padding">0.5em</xsl:attribute>
<!-- prevent page breaks in screen and programlisting tags -->
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
</xsl:attribute-set>
<!-- breaking long lines in code (screen, programlisting) -->
<xsl:attribute-set name="monospace.verbatim.properties">
<xsl:attribute name="wrap-option">wrap</xsl:attribute>
</xsl:attribute-set>
<!-- don't show raw links in [ .. ] after a link -->
<xsl:param name="ulink.show" select="0"/>
<!-- blue underlined hyperlink -->
<xsl:attribute-set name="xref.properties">
<xsl:attribute name="color">blue</xsl:attribute>
<xsl:attribute name="text-decoration">underline</xsl:attribute>
</xsl:attribute-set>
<!-- copyright in range instead of seperated years -->
<xsl:param name="make.year.ranges" select="1" />
<!-- variablelist behavior (asciidoc's term:: lists) -->
<!-- <xsl:param name="variablelist.term.break.after" select="1" /> -->
</xsl:stylesheet>
<!-- vim: set shiftwidth=2 tabstop=2 expandtab: -->

View File

@ -165,6 +165,13 @@
<xsl:attribute name="text-decoration">underline</xsl:attribute>
</xsl:attribute-set>
<!-- strong emphasis in bold -->
<xsl:template match="emphasis[@role='strong']">
<fo:inline font-family="Lato" font-weight="normal">
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<!-- copyright in range instead of seperated years -->
<xsl:param name="make.year.ranges" select="1" />

View File

@ -1,7 +1,7 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 2.2.9 - September 2014</releaseinfo>
<subtitle>for version 2.2.9</subtitle>
<date>2014-09-26</date>
<releaseinfo>Version 2.2.15 - January 2015</releaseinfo>
<subtitle>for version 2.2.15</subtitle>
<date>2015-01-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>

View File

@ -6,13 +6,13 @@
Authors:
- Inverse inc. <info@inverse.ca>
Copyright (C) 2008-2014 Inverse inc.
Copyright (C) 2008-2015 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
////
// TODO have the build system take care of this
:release_version: 2.2.9
:release_version: 2.2.15
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:

View File

@ -6,8 +6,7 @@ include ../Version
ADDITIONAL_OBJCFLAGS += -fPIE
ADDITIONAL_INCLUDE_DIRS +=
ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -fPIE -pie
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -fPIE -pie -Wl,--rpath,$(SOGO_SYSLIBDIR)/sogo
SOGOD = sogod
TOOL_NAME = $(SOGOD)

View File

@ -9,10 +9,9 @@ ADDITIONAL_INCLUDE_DIRS += \
-I..
ADDITIONAL_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework \
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/
SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
-L../SoObjects/SOGo/SOGo.framework/sogo \
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
-L../SOPE/GDLContentStore/$(GNUSTEP_OBJ_DIR)/
$(SOGOD)_TOOL_LIBS += \
-lSOGo \

View File

@ -245,7 +245,7 @@ static BOOL debugLeaks;
}
else
{
NSLog (@"No value specified for '%@'", *urlString);
[self errorWithFormat: @"No value specified for '%@'", *urlString];
ok = NO;
}
}
@ -283,7 +283,7 @@ static BOOL debugLeaks;
{
id authenticator;
if (trustProxyAuthentication)
if (trustProxyAuthentication && [[context request] headerForKey: @"x-webobjects-remote-user"])
authenticator = [SOGoProxyAuthenticator sharedSOGoProxyAuthenticator];
else
{
@ -441,7 +441,7 @@ static BOOL debugLeaks;
if (debugLeaks)
{
if (debugOn)
NSLog (@"allocated classes:\n%s", GSDebugAllocationList (YES));
[self logWithFormat: @"allocated classes:\n%s", GSDebugAllocationList (YES)];
else
{
debugOn = YES;

View File

@ -1,15 +1,15 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2009 Inverse inc.
Copyright (C) 2006-2015 Inverse inc.
This file is part of OpenGroupware.org.
This file is part of SOGo.
OGo is free software; you can redistribute it and/or modify it under
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.

127
NEWS
View File

@ -1,3 +1,126 @@
2.2.15 (2015-01-30)
-------------------
Enhancements
- improved handling of EAS Push when no heartbeat is provided
- no longer need to kill Outlook 2013 when creating EAS profiles (#3076)
- improved server-side CSS cleaner (#3040)
- unified the logging messages in sogo.log file (#2534/#3063)
- updated Brazilian (Portuguese) and Hungarian translations
2.2.14 (2015-01-20)
-------------------
Enhancements
- MultipleBookingsFieldName can be set to -1 to show busy status when booked at least once
- handle multipart objects in EAS/ItemOperations
Bug fixes
- fixed calendar selection in event and task editors (#3049, #3050)
- check for resources existence when listing subscribed ones (#3054)
- correctly recognize Apple Calendar on Yosemite (#2960)
- fixed two potential autorelease pool leaks (#3026 and #3051)
- fixed birthday offset in EAS
- fixed From's full name over EAS
- fixed potential issue when handling multiple Add/Change/Delete/Fetch EAS commands (#3057)
- fixed wrong timezone calculation on recurring events
2.2.13 (2014-12-30)
-------------------
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)
Bug fixes
- fixed contact description truncation on WP8 phones (#3028)
- fixed freebusy information not always returned
- fixed tz issue when the user one was different from the system one with EAS
2.2.12a (2014-12-19)
--------------------
Bug fixes
- fixed empty HTML mails being sent (#3034)
2.2.12 (2014-12-18)
-------------------
New features
- allow including or not freebusy info from subscribed calendars
- now possible to set an autosave timer for draft messages
- now possible to set alarms on event invitations (#76)
Enhancements
- updated CKEditor to version 4.4.6 and added the 'Source Area' plugin
- avoid testing for IMAP ANNOTATION when X-GUID is available (#3018)
- updated Czech, Dutch, Finnish, French, German, Polish and Spanish (Spain) translations
Bug fixes
- fixed for privacy and categories for EAS (#3022)
- correctly set MeetingStatus for EAS on iOS devices
- Ubuntu Lucid fixes for EAS
- fixed calendar reminders for future events (#3008)
- make sure all text parts are UTF-8 re-encoded for Outlook 2013 over EAS (#3003)
- fixed task description truncation affecting WP8 phones over EAS (#3028)
2.2.11a (2014-12-10)
--------------------
Bug fixes
- make sure all address books returned using EAS are GCS ones
2.2.11 (2014-12-09)
-------------------
New features
- sogo-tool can now be used to manage EAS metadata for all devices
Enhancements
- improved the SAML2 documentation
- radically reduced AES memory usage
Bug fixes
- now possible to specify the username attribute for SAML2 (SOGoSAML2LoginAttribute) (#2381)
- added support for IdP-initiated SAML2 logout (#2377)
- we now generate SAML2 metadata on the fly (#2378)
- we now handle correctly the SOGo logout when using SAML (#2376 and #2379)
- fixed freebusy lookups going off bounds for resources (#3010)
- fixed EAS clients moving mails between folders but disconnecting before receiving server's response (#2982)
2.2.10 (2014-11-21)
-------------------
Enhancements
- no longer leaking database passwords in the logs (#2953)
- added support for multiple calendars and address books over ActiveSync
- updated timezone information (#2968)
- updated Brazilian Portuguese, Czech, Dutch, Finnish, French, German, Hungarian, Polish,
Russian, Spanish (Argentina), and Spanish (Spain) translations
- updated CKEditor to version 4.4.5
Bug fixes
- fixed freebusy lookup with "Show time as busy" (#2930)
- don't escape <br>'s in a card's note field
- fixed folder's display name when subscribing to a folder
- fixed folder's display name when the active user subscribes another user to one of her/his folders
- fixed error with new user default sorting value for the mailer module (#2952)
- fixed ActiveSync PING command flooding the server (#2940)
- fixed many interop issues with Windows Phones over ActiveSync
- fixed automatic return receipts crash when not in the recepient list (#2965)
- fixed support for Sieve folder encoding parameter (#2622)
- fixed rename of subscribed addressbooks
- sanitize strings before escaping them when using EAS
- fixed handling of event invitations on iOS/EAS with no organizer (#2978)
- fixed corrupted png files (#2975)
- improved dramatically the BSON decoding speed
- added WindowSize support for GCS collections when using EAS
- fixed IMAP search with non-ASCII folder names
- fixed extraction of email addresses when pasting text with tabs (#2945)
- fixed Outlook attachment corruption issues when using AES (#2957)
2.2.9a (2014-09-29)
-------------------
@ -11,7 +134,7 @@ New features
- support for recurrent tasks (#2160)
- support for alarms on recurrent events / tasks
Enchancements
Enhancements
- alarms can now be snoozed for 1 day
- better iOS/Mac OS X Calendar compability regarding alarms (#1920)
- force default classification over CalDAV if none is set (#2326)
@ -36,7 +159,7 @@ New features
- new user settings for threads collapsing
- IMAP global search support (#2670)
Enchancements
Enhancements
- major refactoring of the GCS component saving code (dropped OGoContentStore)
- printing calendars in colors is now possible in all views; list, daily, weekly and multicolumns
- new option to print calendars events and tasks with a background color or with a border color

View File

@ -141,7 +141,7 @@ $(DBMSGREADER_TOOL)_OBJC_FILES += \
NSObject+PropertyList.m
$(DBMSGREADER_TOOL)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/ -lSOGo \
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
-L../SOPE/GDLContentStore/obj/ -lGDLContentStore \
-L../SOPE/NGCards/obj/ -lNGCards \
-lNGObjWeb
@ -165,12 +165,12 @@ LIBMAPISTORE_LIBS = $(shell pkg-config libmapistore --libs) -lmapiproxy -lWEExte
$(MAPISTORESOGO)_INSTALL_DIR = $(DESTDIR)/$(SAMBA_LIB_DIR)/mapistore_backends
$(MAPISTORESOGO)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/ -lSOGo -lgnustep-base -lobjc -lNGObjWeb \
-L../SoObjects/SOGo/SOGo.framework/sogo/ -lSOGo -lgnustep-base -lobjc -lNGObjWeb \
$(LIBMAPI_LIBS) \
$(LIBMAPISTORE_LIBS)
$(SOGOBACKEND)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/ -lSOGo \
-L../SoObjects/SOGo/SOGo.framework/sogo/ -lSOGo \
$(LIBMAPI_LIBS) \
$(LIBMAPISTORE_LIBS)
@ -183,6 +183,8 @@ ADDITIONAL_INCLUDE_DIRS += \
-DBACKEND_BUNDLE_NAME="@\"$(BUNDLE_NAME)$(BUNDLE_EXTENSION)\"" \
-DSOGO_BUNDLES_DIR="@\"$(BUNDLE_INSTALL_DIR)\""
ADDITIONAL_LDFLAGS += -Wl,--rpath,$(SOGO_SYSLIBDIR)/sogo
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/bundle.make
include $(GNUSTEP_MAKEFILES)/library.make

View File

@ -276,7 +276,7 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60;
EOAdaptorChannel *channel;
GCSChannelHandle *handle;
NSCalendarDate *now, *lastFailure;
NSString *urlId;
NSString *urlId, *url;
channel = nil;
urlId = [_url gcsURLId];
@ -304,10 +304,10 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60;
}
else
{
url = [NSString stringWithFormat: @"%@://%@%@", [_url scheme], [_url host], [_url path]];
if (debugPools)
{
[self logWithFormat: @"DBPOOL: create new DB channel for URL: %@",
[_url absoluteString]];
[self logWithFormat: @"DBPOOL: create new DB channel for %@", url];
}
/* create channel */
@ -330,15 +330,13 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60;
if (lastFailure)
{
[self logWithFormat: @"db for %@ is now back up",
[_url absoluteString]];
[self logWithFormat: @"db for %@ is now back up", url];
[lastFailures removeObjectForKey: urlId];
}
}
else
{
[self errorWithFormat: @"could not open channel %@ for URL: %@",
channel, [_url absoluteString]];
[self errorWithFormat: @"could not open channel %@ for %@", channel, url];
channel = nil;
[lastFailures setObject: now forKey: urlId];
[self warnWithFormat: @" will prevent opening of this"

View File

@ -20,6 +20,7 @@
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
@ -147,7 +148,7 @@
if ([keys count] == 0)
return folderQualifier;
bindings = [_folder valuesForKeys:keys];
bindings = [_folder dictionaryWithValuesForKeys:keys];
return [folderQualifier qualifierWithBindings:bindings
requiresAllVariables:NO];
}

View File

@ -74,6 +74,7 @@ ifneq ($(frameworks),yes)
ifneq ($(FHS_INSTALL_ROOT),)
GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include
endif
GNUSTEP_TARGET_LDIR=sogo
include $(GNUSTEP_MAKEFILES)/library.make
else
include $(GNUSTEP_MAKEFILES)/framework.make

View File

@ -59,8 +59,10 @@ static NGCardsSaxHandler *sax = nil;
[parser setErrorHandler:sax];
}
else
NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
__PRETTY_FUNCTION__);
{
//NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
// __PRETTY_FUNCTION__);
}
}
return parser;
@ -170,8 +172,8 @@ static NGCardsSaxHandler *sax = nil;
{
if (![aChild isKindOfClass: mappedClass])
{
NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
tag, childTag, NSStringFromClass(mappedClass));
//NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
// tag, childTag, NSStringFromClass(mappedClass));
newChild = [aChild elementWithClass: mappedClass];
}
}

View File

@ -131,6 +131,7 @@ ifneq ($(frameworks),yes)
ifneq ($(FHS_INSTALL_ROOT),)
GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include
endif
GNUSTEP_TARGET_LDIR=sogo
include $(GNUSTEP_MAKEFILES)/library.make
else
include $(GNUSTEP_MAKEFILES)/framework.make

View File

@ -54,7 +54,7 @@
- (BOOL)appendLine:(NSString *)_line {
if (self->isFinished) {
NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
//NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
return NO;
}
// limit length to 75 chars

View File

@ -77,8 +77,8 @@ static NSString *gmtcalfmt = @"%Y%m%dT%H%M%SZ";
return [self icalStringInGMT];
else {
/* not in GMT */
NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
__PRETTY_FUNCTION__, _tz);
//NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
// __PRETTY_FUNCTION__, _tz);
return [self icalStringInGMT];
}
}

View File

@ -276,7 +276,9 @@
}
}
else
NSLog(@"Cannot parse iCal duration value: '%@'", self);
{
//NSLog(@"Cannot parse iCal duration value: '%@'", self);
}
if (isNegative)
ti = -ti;

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Abidjan

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Accra

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Addis_Ababa

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Algiers

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Asmara

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Bamako

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Bangui

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Banjul

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Bissau

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Blantyre

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Brazzaville

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Bujumbura

View File

@ -1,14 +1,22 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Cairo
X-LIC-LOCATION:Africa/Cairo
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
TZNAME:EET
DTSTART:19700101T000000
DTSTART:19700924T235959
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1TH
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0300
TZOFFSETTO:+0300
TZNAME:EEST
DTSTART:19700424T010000
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=-1FR
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR

View File

@ -1,22 +1,22 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Casablanca
X-LIC-LOCATION:Africa/Casablanca
BEGIN:DAYLIGHT
TZOFFSETFROM:+0000
TZOFFSETTO:+0100
TZNAME:WEST
DTSTART:19700426T020000
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0100
TZOFFSETTO:+0000
TZNAME:WET
DTSTART:19700927T030000
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0100
TZNAME:WEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Ceuta

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Conakry

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Dakar

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Dar_es_Salaam

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Djibouti

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Douala

View File

@ -1,14 +1,22 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/El_Aaiun
X-LIC-LOCATION:Africa/El_Aaiun
BEGIN:STANDARD
TZOFFSETFROM:+0000
TZOFFSETFROM:+0100
TZOFFSETTO:+0000
TZNAME:WET
DTSTART:19700101T000000
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0100
TZNAME:WEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Freetown

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Gaborone

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Harare

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Johannesburg

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Juba

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Kampala

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Khartoum

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Kigali

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Kinshasa

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Lagos

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Libreville

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Lome

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Luanda

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Lubumbashi

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Lusaka

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Malabo

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Maputo

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Maseru

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Mbabane

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Mogadishu

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Monrovia

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Nairobi

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Ndjamena

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Niamey

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Nouakchott

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Ouagadougou

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Porto-Novo

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Sao_Tome

View File

@ -1,22 +1,14 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Tripoli
X-LIC-LOCATION:Africa/Tripoli
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700327T010000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1FR
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701030T020000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1FR
TZOFFSETTO:+0200
TZNAME:EET
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
END:VCALENDAR

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Tunis

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Africa/Windhoek

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Adak

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Anchorage

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Anguilla

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Antigua

View File

@ -1,22 +1,14 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Araguaina
X-LIC-LOCATION:America/Araguaina
BEGIN:DAYLIGHT
TZOFFSETFROM:-0300
TZOFFSETTO:-0200
TZNAME:BRST
DTSTART:19701018T000000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=3SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0300
TZOFFSETTO:-0300
TZNAME:BRT
DTSTART:19700215T000000
RRULE:FREQ=YEARLY;BYMONTH=2;BYDAY=3SU
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
END:VCALENDAR

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Argentina/Buenos_Aires

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Argentina/Catamarca

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Argentina/Cordoba

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Argentina/Jujuy

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Argentina/La_Rioja

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Argentina/Mendoza

View File

@ -1,5 +1,5 @@
BEGIN:VCALENDAR
PRODID:-//Inverse inc.//NONSGML Olson 2012j//EN
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Argentina/Rio_Gallegos

Some files were not shown because too many files have changed in this diff Show More