Merge pull request #84 from Zentyal/ejhernandez/fix-send-mail-sope-2.2.15
Fix send mail with sope 2.2.15pull/65/merge^2
commit
1178bf2d60
|
@ -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]];
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
@ -517,10 +591,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
softdelete_count++;
|
||||
}
|
||||
|
||||
if (softdelete_count >= theWindowSize)
|
||||
if (softdelete_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
|
||||
{
|
||||
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
|
||||
[self _setFolderMetadata: folderMetadata forKey: [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,10 +733,30 @@ 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:\">"];
|
||||
else
|
||||
|
@ -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];
|
||||
|
@ -966,6 +1084,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
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>"];
|
||||
[output appendString: @"</Collections></Sync>"];
|
||||
|
||||
d = [[output dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
||||
d = [output dataUsingEncoding: NSUTF8StringEncoding];
|
||||
d = [d xml2wbxml];
|
||||
[theResponse setContent: d];
|
||||
}
|
||||
|
||||
[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
|
@ -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];
|
||||
|
||||
|
@ -743,8 +741,6 @@ struct GlobalObjectId {
|
|||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
DESTROY(pool);
|
||||
|
||||
// Attachments -namespace 16
|
||||
attachmentKeys = [self fetchFileAttachmentKeys];
|
||||
if ([attachmentKeys count])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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,13 +231,26 @@ 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
|
||||
if ([self hasAlarms])
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,8 +97,24 @@ 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];
|
||||
|
@ -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"]))
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
---------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">∏</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: -->
|
|
@ -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" />
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
127
NEWS
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -900,7 +900,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
|||
messageBody = MakeMessageBody (properties, attachmentParts, &contentType);
|
||||
if (messageBody)
|
||||
{
|
||||
[headers setObject: contentType forKey: @"content-type"];
|
||||
[message setHeader: contentType forKey: @"content-type"];
|
||||
[message setBody: messageBody];
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -276,7 +276,9 @@
|
|||
}
|
||||
}
|
||||
else
|
||||
NSLog(@"Cannot parse iCal duration value: '%@'", self);
|
||||
{
|
||||
//NSLog(@"Cannot parse iCal duration value: '%@'", self);
|
||||
}
|
||||
|
||||
if (isNegative)
|
||||
ti = -ti;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue