Compare commits
81
Commits
fix_eas
...
SOGo-2.2.17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bbe700dcf | ||
|
|
15ab383770 | ||
|
|
c46e270f80 | ||
|
|
881d99262d | ||
|
|
4d52c9d7e4 | ||
|
|
326635d81b | ||
|
|
ee28801d9a | ||
|
|
88f675bbc6 | ||
|
|
d45c22523e | ||
|
|
5fb8f35951 | ||
|
|
e3e716bb54 | ||
|
|
db20513cf5 | ||
|
|
a64d4bb2cd | ||
|
|
8577cc004f | ||
|
|
4e68ec9d52 | ||
|
|
d82f05de75 | ||
|
|
baba19711b | ||
|
|
99be2b5a12 | ||
|
|
69962862a3 | ||
|
|
6df4d2314f | ||
|
|
364e2fdcdf | ||
|
|
42c382d2f7 | ||
|
|
742ace9252 | ||
|
|
e3a8e17513 | ||
|
|
313ed7f4bc | ||
|
|
8a35aaf47f | ||
|
|
6860ef83ae | ||
|
|
950507626b | ||
|
|
d2634ba783 | ||
|
|
b6144aa29e | ||
|
|
5bbf5ba844 | ||
|
|
7980ddaa29 | ||
|
|
5836785967 | ||
|
|
f6f64728c0 | ||
|
|
1cf1088b93 | ||
|
|
f2289ec17f | ||
|
|
d16eeb1a89 | ||
|
|
3ca94c60d0 | ||
|
|
74b27a771a | ||
|
|
2ae326c41f | ||
|
|
562d3db1a6 | ||
|
|
d3914ae8a8 | ||
|
|
97135f2afa | ||
|
|
3e14825fe2 | ||
|
|
93d190060e | ||
|
|
1f299c7a1a | ||
|
|
74cfb901fd | ||
|
|
065fd5d9b5 | ||
|
|
bf547dd3fe | ||
|
|
81e47c59cd | ||
|
|
7862cda661 | ||
|
|
329552030b | ||
|
|
04904d8c61 | ||
|
|
f0b4a05c70 | ||
|
|
95d6911f1a | ||
|
|
48f98ef34e | ||
|
|
ae0c5eae77 | ||
|
|
0c2d727057 | ||
|
|
072f5f5a15 | ||
|
|
1db85743a0 | ||
|
|
2cf66e037d | ||
|
|
449d838dc2 | ||
|
|
c4bc215a47 | ||
|
|
c9936d7ecf | ||
|
|
885e59a2af | ||
|
|
bf398889bf | ||
|
|
e26e3d7307 | ||
|
|
045b275b27 | ||
|
|
7ec1973e0f | ||
|
|
a79a9c4eff | ||
|
|
f049e2430a | ||
|
|
59b3219f2d | ||
|
|
e9eb8bdc86 | ||
|
|
5e0c7ae4f2 | ||
|
|
c1c0c1ab44 | ||
|
|
a59fff785b | ||
|
|
6a70db80e6 | ||
|
|
d610630c8d | ||
|
|
4dc7790015 | ||
|
|
9dd000a2ca | ||
|
|
ce4084e528 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
Copyright (c) 2015, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -40,35 +40,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@implementation NGMimeMessage (ActiveSync)
|
||||
|
||||
- (NSArray *) allRecipients
|
||||
- (void) _addRecipients: (NSEnumerator *) enumerator
|
||||
toArray: (NSMutableArray *) recipients
|
||||
{
|
||||
NSEnumerator *enumerator, *addressList;
|
||||
NSMutableArray *recipients;
|
||||
NGMailAddressParser *parser;
|
||||
NSEnumerator *addressList;
|
||||
NGMailAddress *address;
|
||||
NSString *s;
|
||||
|
||||
while ((s = [enumerator nextObject]))
|
||||
{
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: s];
|
||||
addressList = [[parser parseAddressList] objectEnumerator];
|
||||
|
||||
while ((address = [addressList nextObject]))
|
||||
[recipients addObject: [address address]];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *) allRecipients
|
||||
{
|
||||
NSMutableArray *recipients;
|
||||
|
||||
recipients = [NSMutableArray array];
|
||||
|
||||
enumerator = [[self headersForKey: @"to"] objectEnumerator];
|
||||
while ((s = [enumerator nextObject]))
|
||||
{
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: s];
|
||||
addressList = [[parser parseAddressList] objectEnumerator];
|
||||
|
||||
while ((address = [addressList nextObject]))
|
||||
[recipients addObject: [address address]];
|
||||
}
|
||||
[self _addRecipients: [[self headersForKey: @"to"] objectEnumerator]
|
||||
toArray: recipients];
|
||||
|
||||
enumerator = [[self headersForKey: @"cc"] objectEnumerator];
|
||||
while ((s = [enumerator nextObject]))
|
||||
{
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: s];
|
||||
addressList = [[parser parseAddressList] objectEnumerator];
|
||||
|
||||
while ((address = [addressList nextObject]))
|
||||
[recipients addObject: [address address]];
|
||||
}
|
||||
[self _addRecipients: [[self headersForKey: @"cc"] objectEnumerator]
|
||||
toArray: recipients];
|
||||
|
||||
[self _addRecipients: [[self headersForKey: @"bcc"] objectEnumerator]
|
||||
toArray: recipients];
|
||||
|
||||
return recipients;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (NSString *) deviceType;
|
||||
- (NSString *) attachmentName;
|
||||
- (NSString *) command;
|
||||
- (NSString *) collectionid;
|
||||
- (NSString *) itemid;
|
||||
- (NSData *) convertHexStringToBytes;
|
||||
|
||||
@end
|
||||
|
||||
@@ -298,6 +298,31 @@ static NSArray *easCommandParameters = nil;
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSString *) itemid
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"ITEMID="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSString *) collectionid
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"COLLECTIONID="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FIXME: combine with our OpenChange code.
|
||||
//
|
||||
|
||||
@@ -540,6 +540,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
{
|
||||
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
|
||||
NSString *davCollectionTagToStore;
|
||||
NSAutoreleasePool *pool;
|
||||
NSMutableString *s;
|
||||
|
||||
@@ -618,6 +619,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
more_available = NO;
|
||||
|
||||
davCollectionTagToStore = [theCollection davCollectionTag];
|
||||
|
||||
switch (theFolderType)
|
||||
{
|
||||
// Handle all the GCS components
|
||||
@@ -788,7 +791,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else
|
||||
{
|
||||
[folderMetadata removeObjectForKey: @"MoreAvailable"];
|
||||
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
|
||||
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
|
||||
}
|
||||
|
||||
[self _setFolderMetadata: folderMetadata
|
||||
@@ -963,7 +966,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else
|
||||
{
|
||||
[folderMetadata removeObjectForKey: @"MoreAvailable"];
|
||||
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
|
||||
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
|
||||
}
|
||||
|
||||
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
||||
@@ -1211,7 +1214,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
// 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]))
|
||||
if (syncKeyInCache && !([davCollectionTag isEqualToString:syncKeyInCache]) && ![davCollectionTag isEqualToString: @"-1"])
|
||||
{
|
||||
davCollectionTag = syncKeyInCache;
|
||||
*changeDetected = YES;
|
||||
@@ -1431,8 +1434,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
}
|
||||
|
||||
// Only send a response if there are changes otherwise send an empty response.
|
||||
if (changeDetected)
|
||||
|
||||
// Only send a response if there are changes or MS-ASProtocolVersion is either 2.5 or 12.0 oterwise send an empty response.
|
||||
if (changeDetected || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"] || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"12.0"])
|
||||
{
|
||||
// We always return the last generated response.
|
||||
// If we only return <Sync><Collections/></Sync>,
|
||||
|
||||
@@ -1127,6 +1127,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
id currentCollection;
|
||||
NSMutableString *s;
|
||||
NSData *d;
|
||||
NSArray *allCollections;
|
||||
int j;
|
||||
|
||||
SOGoMicrosoftActiveSyncFolderType folderType;
|
||||
int status, count;
|
||||
@@ -1135,66 +1137,72 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
status = 1;
|
||||
count = 0;
|
||||
|
||||
collectionId = [[(id)[theDocumentElement getElementsByTagName: @"CollectionId"] lastObject] textValue];
|
||||
realCollectionId = [collectionId realCollectionIdWithFolderType: &folderType];
|
||||
|
||||
if (folderType == ActiveSyncMailFolder)
|
||||
nameInCache = [NSString stringWithFormat: @"folder%@", realCollectionId];
|
||||
else
|
||||
nameInCache = collectionId;
|
||||
|
||||
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
|
||||
|
||||
currentCollection = [self collectionFromId: realCollectionId type: folderType];
|
||||
|
||||
//
|
||||
// For IMAP, we simply build a request like this:
|
||||
//
|
||||
// . UID SORT (SUBJECT) UTF-8 SINCE 1-Jan-2014 NOT DELETED
|
||||
// * SORT 124576 124577 124579 124578
|
||||
// . OK Completed (4 msgs in 0.000 secs)
|
||||
//
|
||||
if (folderType == ActiveSyncMailFolder)
|
||||
{
|
||||
EOQualifier *notDeletedQualifier, *sinceDateQualifier;
|
||||
EOAndQualifier *qualifier;
|
||||
NSCalendarDate *filter;
|
||||
NSArray *uids;
|
||||
|
||||
filter = [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]];
|
||||
|
||||
notDeletedQualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"(not (flags = %@))",
|
||||
@"deleted"];
|
||||
sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"(DATE >= %@)", filter];
|
||||
|
||||
qualifier = [[EOAndQualifier alloc] initWithQualifiers: notDeletedQualifier, sinceDateQualifier,
|
||||
nil];
|
||||
AUTORELEASE(qualifier);
|
||||
|
||||
uids = [currentCollection fetchUIDsMatchingQualifier: qualifier
|
||||
sortOrdering: @"REVERSE ARRIVAL"
|
||||
threaded: NO];
|
||||
count = [uids count];
|
||||
|
||||
// Add the number of UIDs expected to "soft delete"
|
||||
count += [self _softDeleteCountWithFilter: filter collectionId: nameInCache];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
count = [[currentCollection toOneRelationshipKeys] count];
|
||||
}
|
||||
|
||||
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||
[s appendFormat: @"<GetItemEstimate xmlns=\"GetItemEstimate:\"><Response><Status>%d</Status><Collection>", status];
|
||||
[s appendString: @"<GetItemEstimate xmlns=\"GetItemEstimate:\">"];
|
||||
|
||||
allCollections = (id)[theDocumentElement getElementsByTagName: @"Collection"];
|
||||
|
||||
for (j = 0; j < [allCollections count]; j++)
|
||||
{
|
||||
collectionId = [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"CollectionId"] lastObject] textValue];
|
||||
realCollectionId = [collectionId realCollectionIdWithFolderType: &folderType];
|
||||
|
||||
if (folderType == ActiveSyncMailFolder)
|
||||
nameInCache = [NSString stringWithFormat: @"folder%@", realCollectionId];
|
||||
else
|
||||
nameInCache = collectionId;
|
||||
|
||||
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
|
||||
|
||||
currentCollection = [self collectionFromId: realCollectionId type: folderType];
|
||||
|
||||
[s appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
|
||||
[s appendFormat: @"<Estimate>%d</Estimate>", count];
|
||||
//
|
||||
// For IMAP, we simply build a request like this:
|
||||
//
|
||||
// . UID SORT (SUBJECT) UTF-8 SINCE 1-Jan-2014 NOT DELETED
|
||||
// * SORT 124576 124577 124579 124578
|
||||
// . OK Completed (4 msgs in 0.000 secs)
|
||||
//
|
||||
if (folderType == ActiveSyncMailFolder)
|
||||
{
|
||||
NSCalendarDate *filter;
|
||||
NSString *syncKey;
|
||||
NSArray *allMessages;
|
||||
|
||||
filter = [NSCalendarDate dateFromFilterType: [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"FilterType"] lastObject] textValue]];
|
||||
syncKey = [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"SyncKey"] lastObject] textValue];
|
||||
|
||||
allMessages = [currentCollection syncTokenFieldsWithProperties: nil matchingSyncToken: syncKey fromDate: filter];
|
||||
|
||||
count = [allMessages count];
|
||||
|
||||
// Add the number of UIDs expected to "soft delete"
|
||||
count += [self _softDeleteCountWithFilter: filter collectionId: nameInCache];
|
||||
}
|
||||
else
|
||||
{
|
||||
count = [[currentCollection toOneRelationshipKeys] count];
|
||||
}
|
||||
|
||||
|
||||
[s appendString: @"<Response>"];
|
||||
[s appendFormat: @"<Status>%d</Status><Collection>", status];
|
||||
|
||||
if (folderType == ActiveSyncMailFolder)
|
||||
[s appendString: @"<Class>Email</Class>"];
|
||||
else if (folderType == ActiveSyncContactFolder)
|
||||
[s appendString: @"<Class>Contacts</Class>"];
|
||||
else if (folderType == ActiveSyncEventFolder)
|
||||
[s appendString: @"<Class>Calendar</Class>"];
|
||||
else if (folderType == ActiveSyncTaskFolder)
|
||||
[s appendString: @"<Class>Tasks</Class>"];
|
||||
|
||||
[s appendFormat: @"<CollectionId>%@</CollectionId>",collectionId];
|
||||
[s appendFormat: @"<Estimate>%d</Estimate></Collection></Response>", count];
|
||||
}
|
||||
|
||||
[s appendString: @"</Collection></Response></GetItemEstimate>"];
|
||||
[s appendString: @"</GetItemEstimate>"];
|
||||
|
||||
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
||||
|
||||
@@ -1929,6 +1937,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||
[s appendString: @"<Provision xmlns=\"Provision:\">"];
|
||||
[s appendString: @"<AllowHTMLEmail>1</AllowHTMLEmail>"];
|
||||
[s appendString: @"</Provision>"];
|
||||
|
||||
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
||||
@@ -2254,7 +2263,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
error = [self _sendMail: data
|
||||
recipients: [message allRecipients]
|
||||
saveInSentItems: ([(id)[theDocumentElement getElementsByTagName: @"SaveInSentItems"] count] ? YES : NO)];
|
||||
saveInSentItems: ([(id)[theDocumentElement getElementsByTagName: @"SaveInSentItems"] count] ? YES : NO)];
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -2345,7 +2354,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
id value;
|
||||
|
||||
folderId = [[(id)[theDocumentElement getElementsByTagName: @"FolderId"] lastObject] textValue];
|
||||
|
||||
// if folderId is not there try to get it from URL
|
||||
if (!folderId)
|
||||
{
|
||||
folderId = [[[context request] uri] collectionid];
|
||||
}
|
||||
|
||||
itemId = [[(id)[theDocumentElement getElementsByTagName: @"ItemId"] lastObject] textValue];
|
||||
|
||||
// if itemId is not there try to get it from URL
|
||||
if (!itemId)
|
||||
{
|
||||
itemId = [[[context request] uri] itemid];
|
||||
}
|
||||
|
||||
realCollectionId = [folderId realCollectionIdWithFolderType: &folderType];
|
||||
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
|
||||
|
||||
@@ -2543,7 +2566,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// If the MS-ASProtocolVersion header is set to "12.1", the body of the SendMail request is
|
||||
// is a "message/rfc822" payload - otherwise, it's a WBXML blob.
|
||||
//
|
||||
if ([cmdName caseInsensitiveCompare: @"SendMail"] == NSOrderedSame &&
|
||||
if (([cmdName caseInsensitiveCompare: @"SendMail"] == NSOrderedSame ||
|
||||
[cmdName caseInsensitiveCompare: @"SmartReply"] == NSOrderedSame ||
|
||||
[cmdName caseInsensitiveCompare: @"SmartForward"] == NSOrderedSame) &&
|
||||
[[theRequest headerForKey: @"content-type"] caseInsensitiveCompare: @"message/rfc822"] == NSOrderedSame)
|
||||
{
|
||||
NSString *s, *xml;
|
||||
@@ -2561,7 +2586,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
s = [theRequest contentAsString];
|
||||
}
|
||||
|
||||
xml = [NSString stringWithFormat: @"<?xml version=\"1.0\"?><!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\"><SendMail xmlns=\"ComposeMail:\"><SaveInSentItems/><MIME>%@</MIME></SendMail>", [s stringByEncodingBase64]];
|
||||
xml = [NSString stringWithFormat: @"<?xml version=\"1.0\"?><!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\"><%@ xmlns=\"ComposeMail:\"><SaveInSentItems/><MIME>%@</MIME></%@>", cmdName, [s stringByEncodingBase64], cmdName];
|
||||
|
||||
|
||||
|
||||
d = [xml dataUsingEncoding: NSASCIIStringEncoding];
|
||||
}
|
||||
|
||||
@@ -272,10 +272,14 @@ struct GlobalObjectId {
|
||||
charset = [[[self lookupInfoForBodyPart: key] objectForKey: @"parameterList"] objectForKey: @"charset"];
|
||||
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
charset = @"utf-8";
|
||||
|
||||
s = [NSString stringWithData: d usingEncodingNamed: charset];
|
||||
|
||||
// We fallback to ISO-8859-1 string encoding
|
||||
if (!s)
|
||||
s = [[[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding] autorelease];
|
||||
|
||||
if (theType == 1 && *theNativeTypeFound == 2)
|
||||
s = [s htmlToText];
|
||||
|
||||
@@ -323,7 +327,7 @@ struct GlobalObjectId {
|
||||
[[[thePart contentType] type] isEqualToString: @"text"] &&
|
||||
([[[thePart contentType] subType] isEqualToString: @"plain"] || [[[thePart contentType] subType] isEqualToString: @"html"]))
|
||||
{
|
||||
// We make sure everything is encoded in UTF-8
|
||||
// We make sure everything is encoded in UTF-8.
|
||||
NGMimeType *mimeType;
|
||||
NSString *s;
|
||||
|
||||
@@ -334,9 +338,13 @@ struct GlobalObjectId {
|
||||
charset = [[thePart contentType] valueOfParameter: @"charset"];
|
||||
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
charset = @"utf-8";
|
||||
|
||||
s = [NSString stringWithData: body usingEncodingNamed: charset];
|
||||
s = [NSString stringWithData: body usingEncodingNamed: charset];
|
||||
|
||||
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
|
||||
if (!s)
|
||||
s = [[[NSString alloc] initWithData: body encoding: NSISOLatin1StringEncoding] autorelease];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -439,7 +447,7 @@ struct GlobalObjectId {
|
||||
charset = [[[self lookupInfoForBodyPart: @""] objectForKey: @"parameterList"] objectForKey: @"charset"];
|
||||
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
charset = @"utf-8";
|
||||
|
||||
d = [[self fetchPlainTextParts] objectForKey: @""];
|
||||
|
||||
@@ -453,6 +461,10 @@ struct GlobalObjectId {
|
||||
d = [d dataByDecodingQuotedPrintableTransferEncoding];
|
||||
|
||||
s = [NSString stringWithData: d usingEncodingNamed: charset];
|
||||
|
||||
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
|
||||
if (!s)
|
||||
s = [[[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding] autorelease];
|
||||
|
||||
// Check if we must convert html->plain
|
||||
if (theType == 1 && [subtype isEqualToString: @"html"])
|
||||
@@ -469,9 +481,10 @@ struct GlobalObjectId {
|
||||
}
|
||||
else if (theType == 4)
|
||||
{
|
||||
// We sanitize the content *ONLY* for Outlook clients. Outlook has strange issues
|
||||
// We sanitize the content *ONLY* for Outlook clients and if the content-transfer-encoding is 8bit. Outlook has strange issues
|
||||
// with quoted-printable/base64 encoded text parts. It just doesn't decode them.
|
||||
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"])
|
||||
encoding = [[self lookupInfoForBodyPart: @""] objectForKey: @"encoding"];
|
||||
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"] || ([encoding caseInsensitiveCompare: @"8bit"] == NSOrderedSame))
|
||||
d = [self _sanitizedMIMEMessage];
|
||||
else
|
||||
d = [self content];
|
||||
@@ -537,6 +550,10 @@ struct GlobalObjectId {
|
||||
NSData *d, *globalObjId;
|
||||
NSArray *attachmentKeys;
|
||||
NSMutableString *s;
|
||||
|
||||
uint32_t v;
|
||||
NSString *p;
|
||||
|
||||
id value;
|
||||
|
||||
iCalCalendar *calendar;
|
||||
@@ -577,8 +594,25 @@ struct GlobalObjectId {
|
||||
if (value)
|
||||
[s appendFormat: @"<Cc xmlns=\"Email:\">%@</Cc>", [value activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Importance - FIXME
|
||||
[s appendFormat: @"<Importance xmlns=\"Email:\">%@</Importance>", @"1"];
|
||||
// Importance
|
||||
v = 0x1;
|
||||
p = [[self mailHeaders] objectForKey: @"x-priority"];
|
||||
|
||||
if (p)
|
||||
{
|
||||
if ([p hasPrefix: @"1"]) v = 0x2;
|
||||
else if ([p hasPrefix: @"2"]) v = 0x2;
|
||||
else if ([p hasPrefix: @"4"]) v = 0x0;
|
||||
else if ([p hasPrefix: @"5"]) v = 0x0;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = [[self mailHeaders] objectForKey: @"importance"];
|
||||
if ([p hasPrefix: @"High"]) v = 0x2;
|
||||
else if ([p hasPrefix: @"Low"]) v = 0x0;
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Importance xmlns=\"Email:\">%d</Importance>", v];
|
||||
|
||||
// Read
|
||||
[s appendFormat: @"<Read xmlns=\"Email:\">%d</Read>", ([self read] ? 1 : 0)];
|
||||
@@ -753,23 +787,31 @@ struct GlobalObjectId {
|
||||
|
||||
len = [content length];
|
||||
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
|
||||
// Set the correct type if client requested text/html but we got text/plain
|
||||
if (preferredBodyType == 2 && nativeBodyType == 1)
|
||||
[s appendString: @"<Type>1</Type>"];
|
||||
else
|
||||
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
|
||||
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
|
||||
[s appendFormat: @"<Preview></Preview>"];
|
||||
|
||||
if (!truncated)
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Data>%@</Data>", content];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
|
||||
[s appendFormat: @"<Body xmlns=\"Email:\">%@</Body>", content];
|
||||
[s appendFormat: @"<BodyTruncated xmlns=\"Email:\">%d</BodyTruncated>", truncated];
|
||||
}
|
||||
[s appendString: @"</Body>"];
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
|
||||
// Set the correct type if client requested text/html but we got text/plain
|
||||
if (preferredBodyType == 2 && nativeBodyType == 1)
|
||||
[s appendString: @"<Type>1</Type>"];
|
||||
else
|
||||
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
|
||||
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
|
||||
[s appendFormat: @"<Preview></Preview>"];
|
||||
|
||||
if (!truncated)
|
||||
{
|
||||
[s appendFormat: @"<Data>%@</Data>", content];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
|
||||
}
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
// Attachments -namespace 16
|
||||
@@ -777,9 +819,12 @@ struct GlobalObjectId {
|
||||
if ([attachmentKeys count])
|
||||
{
|
||||
int i;
|
||||
|
||||
[s appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
|
||||
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
[s appendString: @"<Attachments xmlns=\"Email:\">"];
|
||||
else
|
||||
[s appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
|
||||
|
||||
for (i = 0; i < [attachmentKeys count]; i++)
|
||||
{
|
||||
value = [attachmentKeys objectAtIndex: i];
|
||||
@@ -790,11 +835,22 @@ struct GlobalObjectId {
|
||||
// FileReference must be a unique identifier across the whole store. We use the following structure:
|
||||
// mail/<foldername>/<message UID/<pathofpart>
|
||||
// mail/INBOX/2
|
||||
[s appendFormat: @"<FileReference>mail/%@/%@/%@</FileReference>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
[s appendFormat: @"<AttName>mail/%@/%@/%@</AttName>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
|
||||
else
|
||||
[s appendFormat: @"<FileReference>mail/%@/%@/%@</FileReference>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
|
||||
|
||||
[s appendFormat: @"<Method>%d</Method>", 1]; // See: http://msdn.microsoft.com/en-us/library/ee160322(v=exchg.80).aspx
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [[value objectForKey: @"size"] intValue]];
|
||||
//[s appendFormat: @"<IsInline>%d</IsInline>", 1];
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<AttMethod>%d</AttMethod>", 1];
|
||||
[s appendFormat: @"<AttSize>%d</AttSize>", [[value objectForKey: @"size"] intValue]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<Method>%d</Method>", 1]; // See: http://msdn.microsoft.com/en-us/library/ee160322(v=exchg.80).aspx
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [[value objectForKey: @"size"] intValue]];
|
||||
//[s appendFormat: @"<IsInline>%d</IsInline>", 1];
|
||||
}
|
||||
[s appendString: @"</Attachment>"];
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
@@ -274,11 +275,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Calendar:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Calendar:\">0</BodyTruncated>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
|
||||
@@ -394,9 +404,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
|
||||
// FIXME: merge with iCalToDo
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
if ((o = [theValues objectForKey: @"Body"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Location"]))
|
||||
[self setLocation: o];
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
@@ -49,6 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
|
||||
@implementation iCalToDo (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
@@ -62,11 +64,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
s = [NSMutableString string];
|
||||
|
||||
// Complete
|
||||
o = [self completed];
|
||||
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", (o ? 1 : 0)];
|
||||
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", [[self status] isEqualToString: @"COMPLETED"] ? 1 : 0];
|
||||
|
||||
// DateCompleted
|
||||
if (o)
|
||||
if ((o = [self completed]))
|
||||
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Start date
|
||||
@@ -97,6 +98,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Reminder - FIXME
|
||||
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
|
||||
|
||||
// Sensitivity
|
||||
if ([[self accessClass] isEqualToString: @"PRIVATE"])
|
||||
v = 2;
|
||||
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
|
||||
@@ -104,6 +106,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else
|
||||
v = 0;
|
||||
|
||||
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", v];
|
||||
|
||||
categories = [self categories];
|
||||
|
||||
if ([categories count])
|
||||
@@ -126,11 +130,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Tasks:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Tasks:\">0</BodyTruncated>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
@@ -152,9 +165,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self setSummary: o];
|
||||
|
||||
// FIXME: merge with iCalEvent
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
if ((o = [theValues objectForKey: @"Body"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
|
||||
if ([[theValues objectForKey: @"Complete"] intValue] &&
|
||||
((o = [theValues objectForKey: @"DateCompleted"])) )
|
||||
@@ -166,6 +186,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[completed setDate: o];
|
||||
[self setStatus: @"COMPLETED"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setStatus: @"IN-PROCESS"];
|
||||
[self setCompleted: nil];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"DueDate"]))
|
||||
{
|
||||
@@ -177,6 +202,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[due setDateTime: o];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"StartDate"]))
|
||||
{
|
||||
iCalDateTime *due;
|
||||
|
||||
o = [o calendarDate];
|
||||
due = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
[due setTimeZone: tz];
|
||||
[due setDateTime: o];
|
||||
}
|
||||
|
||||
// 2 == high, 1 == normal, 0 == low
|
||||
if ((o = [theValues objectForKey: @"Importance"]))
|
||||
{
|
||||
|
||||
@@ -1,3 +1,353 @@
|
||||
commit 097d5c2333515092f03ace5e64fc6824682ba974
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Mar 24 08:40:13 2015 -0400
|
||||
|
||||
now possible to configure objectClass names for LDAP groups using GroupObjectClasses (#1499)
|
||||
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
M NEWS
|
||||
M SoObjects/SOGo/LDAPSource.h
|
||||
M SoObjects/SOGo/LDAPSource.m
|
||||
M SoObjects/SOGo/SOGoGroup.m
|
||||
M SoObjects/SOGo/SOGoSource.h
|
||||
|
||||
commit d75fb0722a0ced5bb937e5b754e95cd0261df7a7
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Mar 24 08:34:29 2015 -0400
|
||||
|
||||
Code cleanups
|
||||
|
||||
M UI/Scheduler/UIxAttendeesEditor.h
|
||||
M UI/Scheduler/UIxAttendeesEditor.m
|
||||
M UI/Scheduler/UIxComponentEditor.h
|
||||
M UI/Scheduler/UIxComponentEditor.m
|
||||
|
||||
commit 26d876e67a32e6c2dc36a3a92449aa0b6638ec41
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Mon Mar 23 16:28:32 2015 -0400
|
||||
|
||||
Improve event attendees editor
|
||||
|
||||
- Avoid repetitive AJAX queries;
|
||||
- Improve handling of daylight changes.
|
||||
|
||||
M UI/WebServerResources/JavascriptAPIExtensions.js
|
||||
M UI/WebServerResources/UIxAttendeesEditor.js
|
||||
|
||||
commit cc3652b59b40bcb420d806412277509ac247d85d
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Mar 23 17:23:29 2015 -0400
|
||||
|
||||
improvements to EAS SyncKey handling to avoid missing mails (#3048, #3058)
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M NEWS
|
||||
|
||||
commit 9d7bbbc312cbe8ccb535e24308be111a3a2eb710
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Mar 23 14:55:14 2015 -0400
|
||||
|
||||
enable by default HTML mails support using EAS on Windows and BB phones
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
|
||||
commit d2915add6d69a8fd05d15bb8c2ed979fe6ad9026
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Mar 23 14:08:31 2015 -0400
|
||||
|
||||
now favor login@domain as the default email address if multiple mail: fields are specified
|
||||
|
||||
M NEWS
|
||||
M SoObjects/SOGo/SOGoUser.h
|
||||
M SoObjects/SOGo/SOGoUser.m
|
||||
|
||||
commit 67139ce3e3f69160a683d8c11bee439be202a84e
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Mar 23 11:35:45 2015 -0400
|
||||
|
||||
improved GetItemEstimate to count all vasnished/deleted mails too
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
|
||||
commit 9eb138b867ebd0a51b9a649891422bac70406510
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Mar 23 10:54:36 2015 -0400
|
||||
|
||||
prevent potential freebusy lookup crashes during timezone changes with repetitive events
|
||||
|
||||
M NEWS
|
||||
M UI/MainUI/SOGoUserHomePage.m
|
||||
|
||||
commit baf3d1f986d48d4fa37a076ccf555d75f4d5dbda
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Fri Mar 20 09:10:49 2015 -0400
|
||||
|
||||
immediately delete mails from EAS clients when they are marked as deleted on the IMAP server
|
||||
|
||||
M NEWS
|
||||
M SoObjects/Mailer/SOGoMailFolder.m
|
||||
|
||||
commit ecd336fa5c6513ee8533dae05e5a328c81527a38
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Fri Mar 20 08:51:35 2015 -0400
|
||||
|
||||
Fix compilation warning and error
|
||||
|
||||
M ActiveSync/NGMimeMessage+ActiveSync.m
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
|
||||
commit afd73289d1ebb13c643f7a8290eac7da43b69330
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Fri Mar 20 08:45:42 2015 -0400
|
||||
|
||||
properly fallback over EAS to UTF-8 and then Latin1 for messages w/o charset (#3103)
|
||||
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit bff21ab1ff136ada7d93cc529a87da9dd254fa60
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Mar 19 16:08:33 2015 -0400
|
||||
|
||||
support for mail prority using EAS
|
||||
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit 6d99226b1390d2dce1f7dfc6a3bab5143aad6364
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Mar 19 14:53:01 2015 -0400
|
||||
|
||||
Always add DisplayName no matter EAS client version
|
||||
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
|
||||
commit 69974807b5740f245376f8e19f71559997bcae44
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Thu Mar 19 08:32:37 2015 -0400
|
||||
|
||||
Fix Language-Region tags in Web interface
|
||||
|
||||
Fixes #3121
|
||||
|
||||
M NEWS
|
||||
M UI/MailerUI/UIxMailEditor.m
|
||||
M UI/Scheduler/UIxCalMainView.m
|
||||
|
||||
commit cdb766e2eff3b6e420da48b3f396814edff96b4f
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Mar 18 10:15:33 2015 -0400
|
||||
|
||||
Documented NGMimeBuildMimeTempDirectory
|
||||
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
|
||||
commit e25a7e3d8d0a5f11a65a6fa337a637b3e1f44432
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Mar 18 09:36:35 2015 -0400
|
||||
|
||||
Fix for bug #3138
|
||||
|
||||
M ActiveSync/NGMimeMessage+ActiveSync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
|
||||
commit 1d5ae27c996f63488653d3a8638b33320540741c
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Tue Mar 17 15:31:35 2015 -0400
|
||||
|
||||
Fix issues with freebusy (Web, busyOffHours)
|
||||
|
||||
M NEWS
|
||||
M SoObjects/Appointments/SOGoFreeBusyObject.m
|
||||
M UI/WebServerResources/UIxAttendeesEditor.js
|
||||
|
||||
commit 1bdd5dfc9085e1f08f839b8179a7ccb37b038e5c
|
||||
Author: Jens Erat <email@jenserat.de>
|
||||
Date: Fri Mar 13 14:06:58 2015 +0100
|
||||
|
||||
Remove obsolete archive string from translations
|
||||
|
||||
M UI/MailerUI/Arabic.lproj/Localizable.strings
|
||||
M UI/MailerUI/Danish.lproj/Localizable.strings
|
||||
M UI/MailerUI/Icelandic.lproj/Localizable.strings
|
||||
M UI/MailerUI/Italian.lproj/Localizable.strings
|
||||
M UI/MailerUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
M UI/MailerUI/Swedish.lproj/Localizable.strings
|
||||
M UI/MailerUI/Ukrainian.lproj/Localizable.strings
|
||||
M UI/MailerUI/Welsh.lproj/Localizable.strings
|
||||
|
||||
commit 37fbd75d552873575f11853e4478d6dce9640201
|
||||
Author: Jens Erat <email@jenserat.de>
|
||||
Date: Fri Mar 13 11:41:07 2015 +0100
|
||||
|
||||
Rename "Archive" to "Export" in Webmail, ctd.
|
||||
|
||||
Fixes #2758 also for non-Inbox folders
|
||||
|
||||
M UI/Templates/MailerUI/UIxMailMainFrame.wox
|
||||
|
||||
commit f1fda8bd0617d5e6b924bb1ae57fb7840bbcc13f
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Tue Mar 10 13:27:17 2015 -0400
|
||||
|
||||
Return a single phone number in JSON contacts list
|
||||
|
||||
M SoObjects/Contacts/SOGoContactSourceFolder.m
|
||||
|
||||
commit 517f4b0f49e2545f930408b922dabc1a4a9006eb
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Mon Mar 9 14:04:21 2015 -0400
|
||||
|
||||
Fix possible JS exception in Contacts module
|
||||
|
||||
M NEWS
|
||||
|
||||
commit cbba0719bb58229d9be8d3bb5af5fba23da3ae14
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Wed Mar 4 10:05:12 2015 -0500
|
||||
|
||||
Fix exception in SOGoUserManager
|
||||
|
||||
M SoObjects/SOGo/SOGoUserManager.m
|
||||
|
||||
commit 8e0849029ea93bfc9e1f9e2cb4ff2e0e5b6a4308
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Tue Mar 3 21:18:46 2015 -0500
|
||||
|
||||
Fix contacts lookup by UID
|
||||
|
||||
When looking for a specific contact UID, we no longer match a pattern
|
||||
that could return multiple results. We search for the exact UID only.
|
||||
|
||||
M NEWS
|
||||
M SoObjects/Appointments/SOGoFreeBusyObject.m
|
||||
M SoObjects/SOGo/SOGoUserManager.h
|
||||
M SoObjects/SOGo/SOGoUserManager.m
|
||||
|
||||
commit 61923225136db72ceb89294d504b65a7f62e7a7f
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Tue Mar 3 20:59:32 2015 -0500
|
||||
|
||||
Fix some gcc warnings
|
||||
|
||||
M SoObjects/SOGo/SOGoCASSession.m
|
||||
M SoObjects/SOGo/SOGoUser.m
|
||||
M SoObjects/SOGo/SOGoUserManager.m
|
||||
|
||||
commit df59b73a221467523c18c56493c13c86003d7271
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:56:42 2015 -0500
|
||||
|
||||
use correct mail attachment elements for EAS 2.5 clients - patch from tfu
|
||||
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit a5672fda5210e6149bd893683c7ee4338f0c3cf9
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:55:36 2015 -0500
|
||||
|
||||
do not use syncKey from cache when davCollectionTag = -1 - patch from tfu
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M NEWS
|
||||
|
||||
commit b593ddc6436e0d4aff2ef24e6ff9b3cda0c0c396
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:53:58 2015 -0500
|
||||
|
||||
SmartReply improvements for missing body attributes - patch from tfu
|
||||
|
||||
M ActiveSync/NSString+ActiveSync.h
|
||||
M ActiveSync/NSString+ActiveSync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
|
||||
commit 38d61f720f0c9352619fa2cb214e81734ed05868
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:52:37 2015 -0500
|
||||
|
||||
use the correct body element for events for EAS 2.5 clients - patch from tfu
|
||||
|
||||
M ActiveSync/iCalEvent+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit 733e334726824be7ab3a41ca7d4b885550a18f9a
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:51:02 2015 -0500
|
||||
|
||||
fixed tasks disappearing issue with RoadSync - patch from tfu
|
||||
|
||||
M ActiveSync/iCalToDo+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit 22888ba5ac2cdc8d52d4c8eba9a94936376b7520
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:49:26 2015 -0500
|
||||
|
||||
use the correct mail body element for EAS 2.5 clients - patch from tfu
|
||||
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit 33c485d2f6d58443c0c67297b87d8cc3d67d1398
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:48:06 2015 -0500
|
||||
|
||||
fixed empty sync responses for EAS 2.5 and 12.0 clients - patch from tfu
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M NEWS
|
||||
|
||||
commit 9160e34134c1c24f5f51cd6c9081723f0963e7c5
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 17:46:34 2015 -0500
|
||||
|
||||
multiple collections support for GetItemEstimate - patch from tfu
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
|
||||
commit 5ceddc213ec08ccb5b44b07aae47921a19b36fd8
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 26 16:00:03 2015 -0500
|
||||
|
||||
Fix for bug #3116
|
||||
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
M NEWS
|
||||
|
||||
commit b97002565e3d21b417f99b704641abee1052642c
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Feb 25 08:42:18 2015 -0500
|
||||
|
||||
Updated NEWS file regarding previous commit
|
||||
|
||||
M NEWS
|
||||
|
||||
commit 8d21bc3e36014d63db0e37bf7121d81c8200b5e1
|
||||
Author: Jesús García Sáez <jgarcia@zentyal.com>
|
||||
Date: Wed Feb 25 12:01:31 2015 +0100
|
||||
|
||||
Fix change password with DomainBasedUID
|
||||
|
||||
When users use full domain to login (SOGoEnableDomainBasedUID) the
|
||||
user attributes in the cache were not being properly updated because
|
||||
in this case the key is `uid@domain` instead of just `uid`.
|
||||
|
||||
M SoObjects/SOGo/SOGoUserManager.m
|
||||
|
||||
commit b26ea30b1b794e983ea272b5de713b0205fda0d8
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 12 11:06:57 2015 -0500
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
M ChangeLog
|
||||
|
||||
commit 72b210cd2ebccc8e9cdc13c23abb76b7f455b780
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Feb 12 10:29:46 2015 -0500
|
||||
|
||||
@@ -1048,6 +1048,11 @@ of supported attributes.
|
||||
user addressbooks (see _abOU_ below), this list of object classes will
|
||||
be applied to new records as they are created.
|
||||
|
||||
|GroupObjectClasses
|
||||
|A list (array) of names identifying groups within the LDAP source. If not
|
||||
set, SOGo will use `group`, `groupofnames`, `groupofuniquenames`
|
||||
and `posixgroup`.
|
||||
|
||||
|modifiers
|
||||
|A list (array) of usernames that are authorized to perform
|
||||
modifications to the address book defined by this LDAP source.
|
||||
@@ -1689,6 +1694,13 @@ cronjob `sogo-tmpwatch`.
|
||||
|
||||
Defaults to `/var/spool/sogo`.
|
||||
|
||||
|S |NGMimeBuildMimeTempDirectory
|
||||
|Parameter used to set the path where temporary files will be stored
|
||||
by SOPE when dealing with MIME messages.
|
||||
|
||||
Defaults to `/tmp`.
|
||||
|
||||
|
||||
|S |NGImap4DisableIMAP4Pooling
|
||||
|Disables IMAP pooling when set to `YES`. Enable pooling by setting to
|
||||
`NO` or using a caching proxy like imapproxy.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- TODO have the build system take care of this -->
|
||||
<releaseinfo>Version 2.2.16 - February 2015</releaseinfo>
|
||||
<subtitle>for version 2.2.16</subtitle>
|
||||
<date>2015-02-12</date>
|
||||
<releaseinfo>Version 2.2.17 - March 2015</releaseinfo>
|
||||
<subtitle>for version 2.2.17</subtitle>
|
||||
<date>2015-03-24</date>
|
||||
|
||||
<legalnotice>
|
||||
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
|
||||
// TODO have the build system take care of this
|
||||
|
||||
:release_version: 2.2.16
|
||||
:release_version: 2.2.17
|
||||
|
||||
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
|
||||
@@ -1,3 +1,35 @@
|
||||
2.2.17 (2015-03-24)
|
||||
-------------------
|
||||
|
||||
Enhancements
|
||||
- support for mail prority using EAS
|
||||
- immediately delete mails from EAS clients when they are marked as deleted on the IMAP server
|
||||
- now favor login@domain as the default email address if multiple mail: fields are specified
|
||||
- enable by default HTML mails support using EAS on Windows and BB phones
|
||||
- now possible to configure objectClass names for LDAP groups using GroupObjectClasses (#1499)
|
||||
|
||||
Bug fixes
|
||||
- fixed login issue after password change (#2601)
|
||||
- fixed potential encoding issue using EAS and 8-bit mails (#3116)
|
||||
- multiple collections support for GetItemEstimate using EAS
|
||||
- fixed empty sync responses for EAS 2.5 and 12.0 clients
|
||||
- use the correct mail body element for EAS 2.5 clients
|
||||
- fixed tasks disappearing issue with RoadSync
|
||||
- use the correct body element for events for EAS 2.5 clients
|
||||
- SmartReply improvements for missing body attributes
|
||||
- do not use syncKey from cache when davCollectionTag = -1
|
||||
- use correct mail attachment elements for EAS 2.5 clients
|
||||
- fixed contacts lookup by UID in freebusy
|
||||
- reduced telephone number to a single value in JSON response of contacts list
|
||||
- fixed freebusy data when 'busy off hours' is enabled and period starts during the weekend
|
||||
- fixed fetching of freebusy data from the Web interface
|
||||
- fixed EAS handling of Bcc in emails (#3138)
|
||||
- fixed Language-Region tags in Web interface (#3121)
|
||||
- properly fallback over EAS to UTF-8 and then Latin1 for messages w/o charset (#3103)
|
||||
- prevent potential freebusy lookup crashes during timezone changes with repetitive events
|
||||
- improved GetItemEstimate to count all vasnished/deleted mails too
|
||||
- improvements to EAS SyncKey handling to avoid missing mails (#3048, #3058)
|
||||
|
||||
2.2.16 (2015-02-12)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -62,17 +62,14 @@
|
||||
SOGoUserManager *um;
|
||||
NSString *domain;
|
||||
NSDictionary *contactInfos;
|
||||
NSArray *contacts;
|
||||
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
contactInfos = [um contactInfosForUserWithUIDorEmail: uid];
|
||||
if (contactInfos == nil)
|
||||
{
|
||||
// Search among global addressbooks
|
||||
domain = [[context activeUser] domain];
|
||||
[um fetchContactsMatching: uid inDomain: domain];
|
||||
contacts = [um fetchContactsMatching: uid inDomain: domain];
|
||||
if ([contacts count] == 1)
|
||||
contactInfos = [contacts lastObject];
|
||||
contactInfos = [um fetchContactWithUID: uid inDomain: domain];
|
||||
}
|
||||
|
||||
/* iCal.app compatibility:
|
||||
@@ -279,7 +276,6 @@
|
||||
if ([uid length])
|
||||
{
|
||||
SOGoUserManager *um;
|
||||
NSArray *contacts;
|
||||
NSString *domain, *email;
|
||||
NSDictionary *contact;
|
||||
MSExchangeFreeBusy *exchangeFreeBusy;
|
||||
@@ -287,10 +283,9 @@
|
||||
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
domain = [[context activeUser] domain];
|
||||
contacts = [um fetchContactsMatching: uid inDomain: domain];
|
||||
if ([contacts count] == 1)
|
||||
contact = [um fetchContactWithUID: uid inDomain: domain];
|
||||
if (contact)
|
||||
{
|
||||
contact = [contacts lastObject];
|
||||
email = [contact valueForKey: @"c_email"];
|
||||
source = [contact objectForKey: @"source"];
|
||||
if ([email length]
|
||||
@@ -386,8 +381,7 @@
|
||||
([currentStartDate compare: startDate] == NSOrderedAscending)? startDate : currentStartDate, @"startDate",
|
||||
currentEndDate, @"endDate", nil]];
|
||||
|
||||
if (!firstRange
|
||||
&& currentEndDate != endDate
|
||||
if (currentEndDate != endDate
|
||||
&& ([currentEndDate dayOfWeek] == 6 || [currentEndDate dayOfWeek] == 0))
|
||||
{
|
||||
// Fill weekend days
|
||||
|
||||
@@ -267,6 +267,13 @@
|
||||
data = [oldRecord objectForKey: @"homephone"];
|
||||
if (![data length])
|
||||
data = @"";
|
||||
else if ([data isKindOfClass: [NSArray class]])
|
||||
{
|
||||
if ([data count] > 0)
|
||||
data = [data objectAtIndex: 0];
|
||||
else
|
||||
data = @"";
|
||||
}
|
||||
[newRecord setObject: data forKey: @"c_telephonenumber"];
|
||||
|
||||
// Custom attribute for group-lookups. See LDAPSource.m where
|
||||
|
||||
@@ -2129,13 +2129,13 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
value: nextModseq];
|
||||
searchQualifier = [[EOAndQualifier alloc]
|
||||
initWithQualifiers:
|
||||
kvQualifier, [self _nonDeletedQualifier], nil];
|
||||
kvQualifier, nil];
|
||||
[kvQualifier release];
|
||||
[searchQualifier autorelease];
|
||||
}
|
||||
else
|
||||
{
|
||||
searchQualifier = [self _nonDeletedQualifier];
|
||||
searchQualifier = nil;
|
||||
}
|
||||
|
||||
if (theStartDate)
|
||||
@@ -2144,7 +2144,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
|
||||
sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
|
||||
@"(DATE >= %@)", theStartDate];
|
||||
searchQualifier = [[EOAndQualifier alloc] initWithQualifiers: searchQualifier, sinceDateQualifier,
|
||||
searchQualifier = [[EOAndQualifier alloc] initWithQualifiers: sinceDateQualifier, searchQualifier,
|
||||
nil];
|
||||
[searchQualifier autorelease];
|
||||
}
|
||||
@@ -2155,7 +2155,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
sortOrdering: nil];
|
||||
|
||||
fetchResults = [(NSDictionary *)[self fetchUIDs: uids
|
||||
parts: [NSArray arrayWithObject: @"modseq"]]
|
||||
parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]]
|
||||
objectForKey: @"fetch"];
|
||||
|
||||
/* NOTE: we sort items manually because Cyrus does not properly sort
|
||||
@@ -2166,7 +2166,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
|
||||
for (i = 0; i < [fetchResults count]; i++)
|
||||
{
|
||||
d = [NSDictionary dictionaryWithObject: [[fetchResults objectAtIndex: i] objectForKey: @"modseq"]
|
||||
d = [NSDictionary dictionaryWithObject: ([[[fetchResults objectAtIndex: i] objectForKey: @"flags"] containsObject: @"deleted"]) ? [NSNull null] : [[fetchResults objectAtIndex: i] objectForKey: @"modseq"]
|
||||
forKey: [[[fetchResults objectAtIndex: i] objectForKey: @"uid"] stringValue]];
|
||||
[allTokens addObject: d];
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
|
||||
NSDictionary *contactMapping;
|
||||
NSArray *contactObjectClasses;
|
||||
NSArray *groupObjectClasses;
|
||||
|
||||
NSDictionary *modulesConstraints;
|
||||
|
||||
@@ -106,6 +107,7 @@
|
||||
UIDField: (NSString *) newUIDField
|
||||
mailFields: (NSArray *) newMailFields
|
||||
searchFields: (NSArray *) newSearchFields
|
||||
groupObjectClasses: (NSArray *) newGroupObjectClasses
|
||||
IMAPHostField: (NSString *) newIMAPHostField
|
||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||
SieveHostField: (NSString *) newSieveHostField
|
||||
|
||||
+29
-11
@@ -101,6 +101,8 @@ static Class NSStringK;
|
||||
contactMapping = nil;
|
||||
searchFields = [NSArray arrayWithObjects: @"sn", @"displayname", @"telephonenumber", nil];
|
||||
[searchFields retain];
|
||||
groupObjectClasses = [NSArray arrayWithObjects: @"group", @"groupofnames", @"groupofuniquenames", @"posixgroup", nil];
|
||||
[groupObjectClasses retain];
|
||||
IMAPHostField = nil;
|
||||
IMAPLoginField = nil;
|
||||
SieveHostField = nil;
|
||||
@@ -144,6 +146,7 @@ static Class NSStringK;
|
||||
[contactMapping release];
|
||||
[mailFields release];
|
||||
[searchFields release];
|
||||
[groupObjectClasses release];
|
||||
[IMAPHostField release];
|
||||
[IMAPLoginField release];
|
||||
[SieveHostField release];
|
||||
@@ -189,6 +192,7 @@ static Class NSStringK;
|
||||
UIDField: [udSource objectForKey: @"UIDFieldName"]
|
||||
mailFields: [udSource objectForKey: @"MailFieldNames"]
|
||||
searchFields: [udSource objectForKey: @"SearchFieldNames"]
|
||||
groupObjectClasses: [udSource objectForKey: @"GroupObjectClasses"]
|
||||
IMAPHostField: [udSource objectForKey: @"IMAPHostFieldName"]
|
||||
IMAPLoginField: [udSource objectForKey: @"IMAPLoginFieldName"]
|
||||
SieveHostField: [udSource objectForKey: @"SieveHostFieldName"]
|
||||
@@ -310,6 +314,7 @@ static Class NSStringK;
|
||||
UIDField: (NSString *) newUIDField
|
||||
mailFields: (NSArray *) newMailFields
|
||||
searchFields: (NSArray *) newSearchFields
|
||||
groupObjectClasses: (NSArray *) newGroupObjectClasses
|
||||
IMAPHostField: (NSString *) newIMAPHostField
|
||||
IMAPLoginField: (NSString *) newIMAPLoginField
|
||||
SieveHostField: (NSString *) newSieveHostField
|
||||
@@ -334,6 +339,8 @@ static Class NSStringK;
|
||||
ASSIGN(mailFields, newMailFields);
|
||||
if (newSearchFields)
|
||||
ASSIGN(searchFields, newSearchFields);
|
||||
if (newGroupObjectClasses)
|
||||
ASSIGN(groupObjectClasses, newGroupObjectClasses);
|
||||
if (newBindFields)
|
||||
{
|
||||
// Before SOGo v1.2.0, bindFields was a comma-separated list
|
||||
@@ -1031,6 +1038,8 @@ static Class NSStringK;
|
||||
NSString *value;
|
||||
static NSArray *resourceKinds = nil;
|
||||
NSMutableArray *classes;
|
||||
NSEnumerator *gclasses;
|
||||
NSString *gclass;
|
||||
id o;
|
||||
|
||||
if (!resourceKinds)
|
||||
@@ -1059,24 +1068,27 @@ static Class NSStringK;
|
||||
|
||||
if (classes)
|
||||
{
|
||||
// We check if our entry is a group. If so, we set the
|
||||
// 'isGroup' custom attribute.
|
||||
if ([classes containsObject: @"group"] ||
|
||||
[classes containsObject: @"groupofnames"] ||
|
||||
[classes containsObject: @"groupofuniquenames"] ||
|
||||
[classes containsObject: @"posixgroup"])
|
||||
{
|
||||
[ldifRecord setObject: [NSNumber numberWithInt: 1]
|
||||
forKey: @"isGroup"];
|
||||
}
|
||||
// We check if our entry is a resource. We also support
|
||||
// determining resources based on the KindFieldName attribute
|
||||
// value - see below.
|
||||
else if ([classes containsObject: @"calendarresource"])
|
||||
if ([classes containsObject: @"calendarresource"])
|
||||
{
|
||||
[ldifRecord setObject: [NSNumber numberWithInt: 1]
|
||||
forKey: @"isResource"];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We check if our entry is a group. If so, we set the
|
||||
// 'isGroup' custom attribute.
|
||||
gclasses = [groupObjectClasses objectEnumerator];
|
||||
while (gclass = [gclasses nextObject])
|
||||
if ([classes containsObject: [gclass lowercaseString]])
|
||||
{
|
||||
[ldifRecord setObject: [NSNumber numberWithInt: 1]
|
||||
forKey: @"isGroup"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We check if that entry corresponds to a resource. For this,
|
||||
@@ -1368,6 +1380,11 @@ static Class NSStringK;
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
- (NSArray *) groupObjectClasses
|
||||
{
|
||||
return groupObjectClasses;
|
||||
}
|
||||
|
||||
static NSArray *
|
||||
_convertRecordToLDAPAttributes (LDAPSourceSchema *schema, NSDictionary *ldifRecord)
|
||||
{
|
||||
@@ -1683,6 +1700,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
UIDField: @"cn"
|
||||
mailFields: nil
|
||||
searchFields: nil
|
||||
groupObjectClasses: nil
|
||||
IMAPHostField: nil
|
||||
IMAPLoginField: nil
|
||||
SieveHostField: nil
|
||||
|
||||
@@ -113,7 +113,6 @@
|
||||
+ (void) handleLogoutRequest: (NSString *) logoutRequest
|
||||
{
|
||||
CASLogoutRequest *rq;
|
||||
SOGoCache *cache;
|
||||
NSBundle *bundle;
|
||||
NSString *mapFile, *sessionIndex;
|
||||
|
||||
|
||||
@@ -137,6 +137,8 @@
|
||||
NGLdapEntry *entry;
|
||||
NSObject <SOGoSource> *source;
|
||||
id o;
|
||||
NSEnumerator *gclasses;
|
||||
NSString *gclass;
|
||||
|
||||
int i;
|
||||
|
||||
@@ -194,12 +196,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Found a group, let's return it.
|
||||
if ([classes containsObject: @"group"] ||
|
||||
[classes containsObject: @"groupofnames"] ||
|
||||
[classes containsObject: @"groupofuniquenames"] ||
|
||||
[classes containsObject: @"posixgroup"])
|
||||
{
|
||||
gclasses = [[source groupObjectClasses] objectEnumerator];
|
||||
while (gclass = [gclasses nextObject])
|
||||
if ([classes containsObject: gclass])
|
||||
{
|
||||
// Found a group, let's return it.
|
||||
o = [[self alloc] initWithIdentifier: theValue
|
||||
domain: domain
|
||||
source: source
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
- (NSString *) baseDN;
|
||||
- (NSString *) MSExchangeHostname;
|
||||
|
||||
- (NSArray *) groupObjectClasses;
|
||||
@end
|
||||
|
||||
#endif /* SOGOSOURCE_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2006-2013 Inverse inc.
|
||||
Copyright (C) 2006-2015 Inverse inc.
|
||||
Copyright (C) 2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOGo.
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <Appointments/SOGoAppointmentFolders.h>
|
||||
#import <Contacts/SOGoContactFolders.h>
|
||||
|
||||
#import "NSArray+Utilities.h"
|
||||
#import "SOGoCache.h"
|
||||
@@ -234,7 +235,6 @@
|
||||
[currentPassword release];
|
||||
[cn release];
|
||||
[loginInDomain release];
|
||||
//[language release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -577,13 +577,13 @@
|
||||
- (void) _appendSystemMailAccount
|
||||
{
|
||||
NSString *fullName, *replyTo, *imapLogin, *imapServer, *cImapServer, *signature,
|
||||
*encryption, *scheme, *action, *query, *customEmail, *sieveServer;
|
||||
*encryption, *scheme, *action, *query, *customEmail, *defaultEmail, *sieveServer;
|
||||
NSMutableDictionary *mailAccount, *identity, *mailboxes, *receipts;
|
||||
NSNumber *port;
|
||||
NSMutableArray *identities;
|
||||
NSArray *mails;
|
||||
NSURL *url, *cUrl;
|
||||
unsigned int count, max;
|
||||
unsigned int count, max, default_identity;
|
||||
NSInteger defaultPort;
|
||||
|
||||
[self userDefaults];
|
||||
@@ -661,8 +661,9 @@
|
||||
[mailAccount setObject: sieveServer forKey: @"sieveServerName"];
|
||||
}
|
||||
|
||||
|
||||
/* identities */
|
||||
// Identities
|
||||
defaultEmail = [NSString stringWithFormat: @"%@@%@", [self loginInDomain], [self domain]];
|
||||
default_identity = 0;
|
||||
identities = [NSMutableArray new];
|
||||
mails = [self allEmails];
|
||||
[mailAccount setObject: [mails objectAtIndex: 0] forKey: @"name"];
|
||||
@@ -702,6 +703,10 @@
|
||||
if (signature)
|
||||
[identity setObject: signature forKey: @"signature"];
|
||||
[identities addObject: identity];
|
||||
|
||||
if ([[identity objectForKey: @"email"] caseInsensitiveCompare: defaultEmail] == NSOrderedSame)
|
||||
default_identity = [identities count]-1;
|
||||
|
||||
[identity release];
|
||||
}
|
||||
}
|
||||
@@ -723,10 +728,14 @@
|
||||
if (signature)
|
||||
[identity setObject: signature forKey: @"signature"];
|
||||
[identities addObject: identity];
|
||||
|
||||
if ([[identity objectForKey: @"email"] caseInsensitiveCompare: defaultEmail] == NSOrderedSame)
|
||||
default_identity = [identities count]-1;
|
||||
|
||||
[identity release];
|
||||
}
|
||||
[[identities objectAtIndex: 0] setObject: [NSNumber numberWithBool: YES]
|
||||
forKey: @"isDefault"];
|
||||
[[identities objectAtIndex: default_identity] setObject: [NSNumber numberWithBool: YES]
|
||||
forKey: @"isDefault"];
|
||||
|
||||
[mailAccount setObject: identities forKey: @"identities"];
|
||||
[identities release];
|
||||
|
||||
@@ -65,10 +65,13 @@
|
||||
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid;
|
||||
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
|
||||
inDomain: (NSString *) domain;
|
||||
- (NSDictionary *) fetchContactWithUID: (NSString *) uid
|
||||
inDomain: (NSString *) domain;
|
||||
- (NSArray *) fetchContactsMatching: (NSString *) match
|
||||
inDomain: (NSString *) domain;
|
||||
- (NSArray *) fetchUsersMatching: (NSString *) filter
|
||||
inDomain: (NSString *) domain;
|
||||
- (NSArray *) _compactAndCompleteContacts: (NSEnumerator *) contacts;
|
||||
|
||||
- (NSString *) getCNForUID: (NSString *) uid;
|
||||
- (NSString *) getEmailForUID: (NSString *) uid;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSException.h>
|
||||
@@ -595,10 +596,11 @@ static Class NSNullK;
|
||||
newPassword: (NSString *) newPassword
|
||||
perr: (SOGoPasswordPolicyError *) perr
|
||||
{
|
||||
NSString *jsonUser;
|
||||
NSString *jsonUser, *userLogin;
|
||||
NSMutableDictionary *currentUser;
|
||||
BOOL didChange;
|
||||
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: login];
|
||||
currentUser = [jsonUser objectFromJSONString];
|
||||
|
||||
@@ -611,9 +613,7 @@ static Class NSNullK;
|
||||
didChange = YES;
|
||||
|
||||
if (!currentUser)
|
||||
{
|
||||
currentUser = [NSMutableDictionary dictionary];
|
||||
}
|
||||
currentUser = [NSMutableDictionary dictionary];
|
||||
|
||||
// It's important to cache the password here as we might have cached the
|
||||
// user's entry in -contactInfosForUserWithUIDorEmail: and if we don't
|
||||
@@ -621,9 +621,13 @@ static Class NSNullK;
|
||||
// cached for the user unless its entry expires from memcached's
|
||||
// internal cache.
|
||||
[currentUser setObject: [newPassword asSHA1String] forKey: @"password"];
|
||||
[[SOGoCache sharedCache]
|
||||
setUserAttributes: [currentUser jsonRepresentation]
|
||||
forLogin: login];
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID])
|
||||
userLogin = [NSString stringWithFormat: @"%@@%@", login, domain];
|
||||
else
|
||||
userLogin = login;
|
||||
[[SOGoCache sharedCache] setUserAttributes: [currentUser jsonRepresentation]
|
||||
forLogin: userLogin];
|
||||
}
|
||||
else
|
||||
didChange = NO;
|
||||
@@ -911,6 +915,37 @@ static Class NSNullK;
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the contact information identified by the specified UID in the global addressbooks.
|
||||
*/
|
||||
- (NSDictionary *) fetchContactWithUID: (NSString *) uid
|
||||
inDomain: (NSString *) domain
|
||||
{
|
||||
NSDictionary *contact;
|
||||
NSMutableArray *contacts;
|
||||
NSEnumerator *sources;
|
||||
NSString *sourceID;
|
||||
id currentSource;
|
||||
|
||||
contacts = [NSMutableArray array];
|
||||
contact = nil;
|
||||
sources = [[self addressBookSourceIDsInDomain: domain] objectEnumerator];
|
||||
while ((sourceID = [sources nextObject]))
|
||||
{
|
||||
currentSource = [_sources objectForKey: sourceID];
|
||||
contact = [currentSource lookupContactEntry: uid];
|
||||
if (contact)
|
||||
[contacts addObject: contact];
|
||||
}
|
||||
|
||||
if ([contacts count])
|
||||
contact = [[self _compactAndCompleteContacts: [contacts objectEnumerator]] lastObject];
|
||||
else
|
||||
contact = nil;
|
||||
|
||||
return contact;
|
||||
}
|
||||
|
||||
- (NSArray *) _compactAndCompleteContacts: (NSEnumerator *) contacts
|
||||
{
|
||||
NSMutableDictionary *compactContacts, *returnContact;
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
"Remove this folder" = "مسح المجلد";
|
||||
"Erase mails from this folder" = "مسح الرسائل من هذا المجلد";
|
||||
"Expunge this folder" = "محو هذا المجلد";
|
||||
"Archive This Folder" = "أرشفة هذا المجلد";
|
||||
"Modify the acl of this folder" = "تعديل قائمة الصلاحيات لهذا المجلد";
|
||||
|
||||
"Saved Messages.zip" = "حفظ Messages.zip";
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
"Remove this folder" = "Fjern denne mappe";
|
||||
"Erase mails from this folder" = "Slet beskeder fra denne mappe";
|
||||
"Expunge this folder" = "Slet denne mappe";
|
||||
"Archive This Folder" = "Gem denne mappe";
|
||||
"Modify the acl of this folder" = "Rediger ACL i denne mappe";
|
||||
|
||||
"Saved Messages.zip" = "Gemte beskeder.zip";
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
"Remove this folder" = "Fjarlægja þessa möppu";
|
||||
"Erase mails from this folder" = "Eyða bréfum úr þessari möppu";
|
||||
"Expunge this folder" = "Afmá allt í þessari möppu";
|
||||
"Archive This Folder" = "Setja þessa möppu í geymslu";
|
||||
"Modify the acl of this folder" = "Breyta aðgangsstýringum fyrir þessa möppu";
|
||||
|
||||
"Saved Messages.zip" = "vistud_skilabod.zip";
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
"Remove this folder" = "Rimuovi questa cartella";
|
||||
"Erase mails from this folder" = "Elimina emails da questa cartella";
|
||||
"Expunge this folder" = "Pulisci questa cartella";
|
||||
"Archive This Folder" = "Archivia questa cartella";
|
||||
"Modify the acl of this folder" = "Modifica i permessi per questa cartella";
|
||||
|
||||
"Saved Messages.zip" = "Salvato Messages.zip";
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
"Remove this folder" = "Ta bort mappen";
|
||||
"Erase mails from this folder" = "Slett meldinger fra mappen";
|
||||
"Expunge this folder" = "Fjern mappen";
|
||||
"Archive This Folder" = "Arkiver denne mappen";
|
||||
"Modify the acl of this folder" = "Endre adgangsrettigheter til mappen";
|
||||
|
||||
"Saved Messages.zip" = "Lagrete Meldinger.zip";
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
"Remove this folder" = "Ta bort mappen";
|
||||
"Erase mails from this folder" = "Radera meddelanden från mappen";
|
||||
"Expunge this folder" = "Radera mappen";
|
||||
"Archive This Folder" = "Arkivera mappen";
|
||||
"Modify the acl of this folder" = "Ändra åtkomsträttigheter på mappen";
|
||||
|
||||
"Saved Messages.zip" = "Sparat Messages.zip";
|
||||
|
||||
@@ -230,7 +230,9 @@ static NSArray *infoKeys = nil;
|
||||
- (NSString *) localeCode
|
||||
{
|
||||
// WARNING : NSLocaleCode is not defined in <Foundation/NSUserDefaults.h>
|
||||
return [locale objectForKey: @"NSLocaleCode"];
|
||||
// Region subtag must be separated by a dash
|
||||
NSString *s = [locale objectForKey: @"NSLocaleCode"];
|
||||
return [s stringByReplacingOccurrencesOfString: @"_" withString: @"-"];
|
||||
}
|
||||
|
||||
- (void) setFrom: (NSString *) newFrom
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
"Remove this folder" = "Вилучати цю теку";
|
||||
"Erase mails from this folder" = "Вилучати повідомлення з цієї теки";
|
||||
"Expunge this folder" = "Позначати листи як вилучені";
|
||||
"Archive This Folder" = "Архівувати цю теку";
|
||||
"Modify the acl of this folder" = "Керувати правами доступу до цієї теки";
|
||||
|
||||
"Saved Messages.zip" = "Збережено Messages.zip";
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
"Remove this folder" = "Dileu'r ffolder hwn";
|
||||
"Erase mails from this folder" = "Dileu ebost o'r ffolder hwn";
|
||||
"Expunge this folder" = "Dileu'r ffolder hwn";
|
||||
"Archive This Folder" = "Archive This Folder";
|
||||
"Modify the acl of this folder" = "Newid acl y ffolder";
|
||||
|
||||
"Saved Messages.zip" = "Saved Messages.zip";
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
|
||||
delta = [[currentDate timeZoneDetail] timeZoneSecondsFromGMT] - [[startDate timeZoneDetail] timeZoneSecondsFromGMT];
|
||||
startInterval += (delta/60/15);
|
||||
startInterval = (startInterval < -4 ? -4 : startInterval);
|
||||
|
||||
currentDate = [record objectForKey: @"endDate"];
|
||||
if ([currentDate earlierDate: endDate] == endDate)
|
||||
@@ -165,6 +166,8 @@
|
||||
|
||||
delta = [[currentDate timeZoneDetail] timeZoneSecondsFromGMT] - [[startDate timeZoneDetail] timeZoneSecondsFromGMT];
|
||||
endInterval += (delta/60/15);
|
||||
endInterval = (endInterval < 0 ? 0 : endInterval);
|
||||
endInterval = (endInterval > itemCount+4 ? itemCount+4 : endInterval);
|
||||
|
||||
// Update bit string representation
|
||||
// If the user is a resource with restristed amount of bookings, keep the sum of overlapping events
|
||||
@@ -230,7 +233,7 @@
|
||||
intervals = interval / intervalSeconds + 8;
|
||||
|
||||
// Build a bit string representation of the freebusy data for the period
|
||||
freeBusyItems = NSZoneCalloc (NULL, intervals, sizeof (int));
|
||||
freeBusyItems = calloc(intervals, sizeof (unsigned int));
|
||||
[self _fillFreeBusyItems: (freeBusyItems+4)
|
||||
count: (intervals-4)
|
||||
withRecords: [fb fetchFreeBusyInfosFrom: start to: end forContact: uid]
|
||||
@@ -243,7 +246,7 @@
|
||||
{
|
||||
[freeBusy addObject: [NSString stringWithFormat: @"%d", *(freeBusyItems + count)]];
|
||||
}
|
||||
NSZoneFree (NULL, freeBusyItems);
|
||||
free(freeBusyItems);
|
||||
|
||||
// Return a NSString representation
|
||||
return [freeBusy componentsJoinedByString: @","];
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* UIxAttendeesEditor.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* UIxAttendeesEditor.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2007-2015 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -82,7 +82,9 @@
|
||||
- (NSString *) localeCode
|
||||
{
|
||||
// WARNING : NSLocaleCode is not defined in <Foundation/NSUserDefaults.h>
|
||||
return [locale objectForKey: @"NSLocaleCode"];
|
||||
// Region subtag must be separated by a dash
|
||||
NSString *s = [locale objectForKey: @"NSLocaleCode"];
|
||||
return [s stringByReplacingOccurrencesOfString: @"_" withString: @"-"];
|
||||
}
|
||||
|
||||
- (NSArray *) monthMenuItems
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* UIxComponentEditor.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2014 Inverse inc.
|
||||
* Copyright (C) 2006-2015 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -176,7 +176,6 @@ iRANGE(2);
|
||||
[self setIsCycleEndNever];
|
||||
componentOwner = @"";
|
||||
organizer = nil;
|
||||
//organizerIdentity = nil;
|
||||
organizerProfile = nil;
|
||||
ownerAsAttendee = nil;
|
||||
attendee = nil;
|
||||
@@ -213,7 +212,6 @@ iRANGE(2);
|
||||
[title release];
|
||||
[location release];
|
||||
[organizer release];
|
||||
//[organizerIdentity release];
|
||||
[organizerProfile release];
|
||||
[ownerAsAttendee release];
|
||||
[comment release];
|
||||
@@ -820,25 +818,27 @@ iRANGE(2);
|
||||
uid = email;
|
||||
|
||||
[profile setObject: name
|
||||
forKey: @"name"];
|
||||
forKey: @"name"];
|
||||
|
||||
[profile setObject: email
|
||||
forKey: @"email"];
|
||||
forKey: @"email"];
|
||||
|
||||
if (partstat == nil || ![partstat length])
|
||||
partstat = @"accepted";
|
||||
|
||||
[profile setObject: partstat
|
||||
forKey: @"partstat"];
|
||||
forKey: @"partstat"];
|
||||
|
||||
if (role == nil || ![role length])
|
||||
role = @"chair";
|
||||
|
||||
[profile setObject: role
|
||||
forKey: @"role"];
|
||||
forKey: @"role"];
|
||||
|
||||
organizerProfile = [NSDictionary dictionaryWithObject: profile forKey: uid];
|
||||
[organizerProfile retain];
|
||||
}
|
||||
|
||||
|
||||
return organizerProfile;
|
||||
}
|
||||
|
||||
@@ -897,30 +897,6 @@ iRANGE(2);
|
||||
return [[[[self organizerProfile] allValues] lastObject] jsonRepresentation];
|
||||
}
|
||||
|
||||
// - (BOOL) canBeOrganizer
|
||||
// {
|
||||
// NSString *owner;
|
||||
// SOGoObject <SOGoComponentOccurence> *co;
|
||||
// SOGoUser *currentUser;
|
||||
// BOOL hasOrganizer;
|
||||
// SoSecurityManager *sm;
|
||||
|
||||
// co = [self clientObject];
|
||||
// owner = [co ownerInContext: context];
|
||||
// currentUser = [context activeUser];
|
||||
|
||||
// hasOrganizer = ([[organizer value: 0] length] > 0);
|
||||
|
||||
// sm = [SoSecurityManager sharedSecurityManager];
|
||||
|
||||
// return ([co isNew]
|
||||
// || (([owner isEqualToString: [currentUser login]]
|
||||
// || ![sm validatePermission: SOGoCalendarPerm_ModifyComponent
|
||||
// onObject: co
|
||||
// inContext: context])
|
||||
// && (!hasOrganizer || [component userIsOrganizer: currentUser])));
|
||||
// }
|
||||
|
||||
- (BOOL) hasOrganizer
|
||||
{
|
||||
// We check if there's an organizer and if it's not ourself
|
||||
@@ -948,51 +924,8 @@ iRANGE(2);
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
//return ([[organizer value: 0] length] && ![self canBeOrganizer]);
|
||||
}
|
||||
|
||||
//- (void) setOrganizerIdentity: (NSDictionary *) newOrganizerIdentity
|
||||
//{
|
||||
// ASSIGN (organizerIdentity, newOrganizerIdentity);
|
||||
//}
|
||||
|
||||
// - (NSDictionary *) organizerIdentity
|
||||
// {
|
||||
// NSArray *allIdentities;
|
||||
// NSEnumerator *identities;
|
||||
// NSDictionary *currentIdentity;
|
||||
// NSString *orgEmail;
|
||||
|
||||
// orgEmail = [organizer rfc822Email];
|
||||
// if (!organizerIdentity)
|
||||
// {
|
||||
// if ([orgEmail length])
|
||||
// {
|
||||
// allIdentities = [[context activeUser] allIdentities];
|
||||
// identities = [allIdentities objectEnumerator];
|
||||
// while (!organizerIdentity
|
||||
// && ((currentIdentity = [identities nextObject])))
|
||||
// if ([[currentIdentity objectForKey: @"email"]
|
||||
// caseInsensitiveCompare: orgEmail]
|
||||
// == NSOrderedSame)
|
||||
// ASSIGN (organizerIdentity, currentIdentity);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return organizerIdentity;
|
||||
// }
|
||||
|
||||
//- (NSArray *) organizerList
|
||||
//{
|
||||
// return [[context activeUser] allIdentities];
|
||||
//}
|
||||
|
||||
//- (NSString *) itemOrganizerText
|
||||
//{
|
||||
// return [item keysWithFormat: @"%{fullName} <%{email}>"];
|
||||
//}
|
||||
|
||||
- (BOOL) hasAttendees
|
||||
{
|
||||
return ([[component attendees] count] > 0);
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
<li><var:string label:value="Mark Folder Read" /></li>
|
||||
<li><var:string label:value="New Subfolder..." /></li>
|
||||
<li><var:string label:value="Compact This Folder" /></li>
|
||||
<li><var:string label:value="Archive This Folder" /></li>
|
||||
<li><var:string label:value="Export This Folder" /></li>
|
||||
<li><var:string label:value="Empty Trash" /></li>
|
||||
<li><!-- separator --></li>
|
||||
<li><var:string label:value="Search Messages..." /></li>
|
||||
@@ -103,7 +103,7 @@
|
||||
<li><var:string label:value="New Subfolder..." /></li>
|
||||
<li><var:string label:value="Rename Folder..." /></li>
|
||||
<li><var:string label:value="Compact This Folder" /></li>
|
||||
<li><var:string label:value="Archive This Folder" /></li>
|
||||
<li><var:string label:value="Export This Folder" /></li>
|
||||
<li><var:string label:value="Delete Folder" /></li>
|
||||
<li><var:string label:value="Use This Folder For" /></li>
|
||||
<li><!-- separator --></li>
|
||||
|
||||
@@ -218,7 +218,7 @@ Date.prototype.stringWithSeparator = function(separator) {
|
||||
|
||||
Date.prototype.addDays = function(nbrDays) {
|
||||
var milliSeconds = this.getTime();
|
||||
milliSeconds += 86400000 * nbrDays;
|
||||
milliSeconds += 86400000 * Math.round(nbrDays);
|
||||
this.setTime(milliSeconds);
|
||||
};
|
||||
|
||||
|
||||
@@ -896,9 +896,8 @@ _freeBusyCacheEntry.prototype = {
|
||||
if (this.entries.length > offset) {
|
||||
var adjustedEd = ed.beginOfDay();
|
||||
var nbrDays = adjustedSd.deltaDays(adjustedEd) + 1;
|
||||
var nbrQu = nbrDays * 96;
|
||||
var offsetEnd = offset + nbrQu;
|
||||
if (this.entries.length >= offsetEnd) {
|
||||
var offsetEnd = offset + (nbrDays * 96);
|
||||
if (Math.round(this.entries.length/96) >= nbrDays) {
|
||||
entries = this.entries.slice(offset, offsetEnd);
|
||||
}
|
||||
}
|
||||
@@ -912,15 +911,19 @@ _freeBusyCacheEntry.prototype = {
|
||||
|
||||
var adjustedSd = sd.beginOfDay();
|
||||
var adjustedEd = ed.beginOfDay();
|
||||
var nbrDays = adjustedSd.deltaDays(adjustedEd) + 1;
|
||||
var start = adjustedSd.clone();
|
||||
start.addDays(-7);
|
||||
var end = adjustedEd.clone();
|
||||
end.addDays(7);
|
||||
if (this.startDate) {
|
||||
fetchDates = [];
|
||||
|
||||
if (adjustedSd.getTime() < this.startDate.getTime()) {
|
||||
var start = adjustedSd.clone();
|
||||
start.addDays(-7);
|
||||
var end = this.startDate.beginOfDay();
|
||||
end.addDays(-1);
|
||||
// Period extends to before current start
|
||||
if (end.getTime() >= this.startDate.getTime()) {
|
||||
end = this.startDate.beginOfDay();
|
||||
end.addDays(-1);
|
||||
}
|
||||
fetchDates.push({ start: start, end: end });
|
||||
}
|
||||
|
||||
@@ -928,16 +931,16 @@ _freeBusyCacheEntry.prototype = {
|
||||
var nextDate = this.startDate.clone();
|
||||
nextDate.addDays(currentNbrDays);
|
||||
if (adjustedEd.getTime() >= nextDate.getTime()) {
|
||||
var end = nextDate.clone();
|
||||
end.addDays(7);
|
||||
fetchDates.push({ start: nextDate, end: end });
|
||||
// Period extends to after current end
|
||||
if (start.getTime() <= nextDate.getTime()) {
|
||||
start = nextDate.beginOfDay();
|
||||
start.addDays(1);
|
||||
}
|
||||
fetchDates.push({ start: start, end: end });
|
||||
}
|
||||
}
|
||||
else {
|
||||
var start = adjustedSd.clone();
|
||||
start.addDays(-7);
|
||||
var end = adjustedEd.clone();
|
||||
end.addDays(7);
|
||||
// Initial range
|
||||
fetchDates = [ { start: start, end: end } ];
|
||||
}
|
||||
|
||||
@@ -945,18 +948,27 @@ _freeBusyCacheEntry.prototype = {
|
||||
},
|
||||
|
||||
integrateEntries: function fBCE_integrateEntries(entries, start, end) {
|
||||
var days, merged = false;
|
||||
if (this.startDate) {
|
||||
if (start.getTime() < this.startDate) {
|
||||
var days = start.deltaDays(this.startDate);
|
||||
days = start.deltaDays(this.startDate);
|
||||
if (entries.length == (days * 96)) {
|
||||
// New period is just before previous period
|
||||
this.startDate = start;
|
||||
this.entries = entries.concat(this.entries);
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.entries = this.entries.concat(entries);
|
||||
days = this.startDate.deltaDays(start);
|
||||
if (Math.round(this.entries.length/96) == days) {
|
||||
// New period is just after previous period
|
||||
this.entries = this.entries.concat(entries);
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (!merged) {
|
||||
this.startDate = start;
|
||||
this.entries = entries;
|
||||
}
|
||||
@@ -1193,7 +1205,7 @@ function drawFbData(input, slots) {
|
||||
else {
|
||||
log("inconsistency between freebusy results and"
|
||||
+ " the number of cells");
|
||||
log(" expecting: " + tds.length + " received: " + slots.length);
|
||||
log(" expecting: " + (tds.length * 4) + " received: " + slots.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1674,10 +1686,10 @@ function initTimeWidgets(widgets) {
|
||||
function onAdjustTime(event) {
|
||||
var endDate = window.getEndDate();
|
||||
var startDate = window.getStartDate();
|
||||
var delta = 0;
|
||||
if (this.id.startsWith("start")) {
|
||||
// Start date was changed
|
||||
var delta = window.getShadowStartDate().valueOf() -
|
||||
startDate.valueOf();
|
||||
delta = window.getShadowStartDate().valueOf() - startDate.valueOf();
|
||||
var newEndDate = new Date(endDate.valueOf() - delta);
|
||||
window.setEndDate(newEndDate);
|
||||
window.timeWidgets['end']['date'].updateShadowValue();
|
||||
@@ -1687,20 +1699,27 @@ function onAdjustTime(event) {
|
||||
}
|
||||
else {
|
||||
// End date was changed
|
||||
var delta = endDate.valueOf() - startDate.valueOf();
|
||||
if (delta < 0) {
|
||||
showAlertDialog(labels.validate_endbeforestart);
|
||||
var oldEndDate = window.getShadowEndDate();
|
||||
window.setEndDate(oldEndDate);
|
||||
|
||||
window.timeWidgets['end']['date'].updateShadowValue();
|
||||
window.timeWidgets['end']['time'].updateShadowValue();
|
||||
window.timeWidgets['end']['time'].onChange(); // method from SOGoTimePicker
|
||||
delta = window.getShadowEndDate().valueOf() - endDate.valueOf();
|
||||
if (delta != 0) {
|
||||
var startEndDelta = endDate.valueOf() - startDate.valueOf();
|
||||
if (startEndDelta < 0) {
|
||||
showAlertDialog(labels.validate_endbeforestart);
|
||||
var oldEndDate = window.getShadowEndDate();
|
||||
window.setEndDate(oldEndDate);
|
||||
window.timeWidgets['end']['date'].updateShadowValue();
|
||||
window.timeWidgets['end']['time'].updateShadowValue();
|
||||
window.timeWidgets['end']['time'].onChange(); // method from SOGoTimePicker
|
||||
}
|
||||
else {
|
||||
window.timeWidgets['end']['date'].updateShadowValue();
|
||||
window.timeWidgets['end']['time'].updateShadowValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specific function for the attendees editor
|
||||
onTimeDateWidgetChange();
|
||||
if ($("freeBusyHeader").getElementsByTagName("th").length == 0 || delta != 0)
|
||||
// Update freebusy data
|
||||
onTimeDateWidgetChange();
|
||||
}
|
||||
|
||||
function _getDate(which) {
|
||||
@@ -1739,6 +1758,7 @@ function getShadowEndDate() {
|
||||
|
||||
function _setDate(which, newDate) {
|
||||
window.timeWidgets[which]['date'].setInputAsDate(newDate);
|
||||
jQuery(window.timeWidgets[which]['date']).closest('.date').datepicker('update');
|
||||
if (!isAllDay) {
|
||||
window.timeWidgets[which]['time'].value = newDate.getDisplayHoursString();
|
||||
if (window.timeWidgets[which]['time'].onChange) window.timeWidgets[which]['time'].onChange(); // method from SOGoTimePicker
|
||||
|
||||
Reference in new issue
Block a user