Compare commits

...
75 Commits
Author SHA1 Message Date
Ludovic Marcotte d16eeb1a89 Merge to 2.2.16 2015-02-12 11:07:36 -05:00
Ludovic Marcotte b26ea30b1b Update ChangeLog 2015-02-12 11:06:57 -05:00
Ludovic Marcotte 72b210cd2e Fixed typo 2015-02-12 10:29:46 -05:00
Ludovic Marcotte a80d75d09c Preparation for the release 2015-02-12 10:27:10 -05:00
Ludovic Marcotte aae76dc4e6 Limit curl request for webcalendars to 60 seconds 2015-02-12 09:57:10 -05:00
Francis Lachapelle c20ca0e33d Fix exception in set operation of sogo-tool 2015-02-12 09:29:40 -05:00
Francis Lachapelle 601a9ca559 Update translations 2015-02-12 09:09:18 -05:00
Ludovic Marcotte d7c283f751 improved fetching of text parts over EAS 2015-02-12 08:49:17 -05:00
Ludovic Marcotte f3325b8b0d Updated NEWS file wrt fixes 2015-02-11 18:13:36 -05:00
Ludovic Marcotte b4ea4d7e9f Improvement over previous commit 2015-02-11 14:39:57 -05:00
Ludovic Marcotte 9447437d6f Added missing strings from previous commit 2015-02-11 14:33:32 -05:00
Ludovic Marcotte 322f72626a now possible to limit automatic forwards to internal/external domains 2015-02-11 14:30:40 -05:00
Ludovic Marcotte 55ae4cb8c0 First pass at EAS' best practices for SOGo 2015-02-11 12:59:04 -05:00
Ludovic Marcotte e5d01428ad now possible for SOGo to change the sambaNTPassword/sambaLMPassword 2015-02-11 11:31:35 -05:00
Ludovic Marcotte 82178fd6ce Initial patch from tfu for bug #3055 2015-02-11 08:31:32 -05:00
Ludovic Marcotte 6cf1ec998e Updated NEWS file for the #3095 bug fix in SOPE 2015-02-10 07:09:31 -05:00
Ludovic Marcotte 6c9b1a494f Fix for bug #2332 2015-02-09 16:12:59 -05:00
Ludovic Marcotte 98e4c8ca55 Fixed doc regarder domain vs. system settings 2015-02-09 09:10:55 -05:00
Ludovic Marcotte 3731819e15 Added patch from tfu for #2995 2015-02-05 16:21:27 -05:00
Ludovic Marcotte eca22caefc Fix for bug #3078 2015-02-05 11:14:53 -05:00
Ludovic Marcotte 923bcf8ae2 Applied patch for #3092 2015-02-05 09:29:29 -05:00
Francis Lachapelle 0b44fa81f4 Update NEWS file 2015-02-03 13:20:57 -05:00
Francis Lachapelle 776b17ff20 Fix mail editor when not called from mail module
Fixes #3088
2015-02-03 12:06:28 -05:00
Ludovic Marcotte 3ca94c60d0 Merge to 2.2.15 2015-01-30 11:10:11 -05:00
Ludovic Marcotte 2aa528dacc Preparation for the release 2015-01-30 11:08:43 -05:00
Francis Lachapelle d1d3980919 Update translations 2015-01-30 11:03:38 -05:00
Ludovic Marcotte cf35eec1f5 Improved the NEWS file for the release 2015-01-30 10:28:45 -05:00
Ludovic Marcotte 58a0b0c173 Updated for the release 2015-01-30 10:23:04 -05:00
Ludovic Marcotte 723a9d4e08 Reverted bug fix from #3054 and added comment 2015-01-29 16:21:06 -05:00
Francis Lachapelle 4cc158043e Improve CSS server-side cleaner
Fixes #3040
2015-01-28 16:38:27 -05:00
Ludovic Marcotte 7fd1564a86 fix for #3076 2015-01-28 15:16:21 -05:00
Ludovic Marcotte 981c718d22 improved handling of EAS Push when no heartbeat is provided 2015-01-28 15:03:49 -05:00
Ludovic Marcotte 086361b79a Avoid GNUstep warnings 2015-01-23 16:16:36 -05:00
Ludovic Marcotte ab12c84887 More NSLog usage cleanups 2015-01-23 15:32:22 -05:00
Ludovic Marcotte e2bee23021 Avoid unnecessary calls to NSLog 2015-01-22 16:25:16 -05:00
Ludovic Marcotte 1a10599369 Removed unnecessary NSLog calls 2015-01-22 15:39:57 -05:00
Ludovic Marcotte d907d5d268 Avoid using NSLog() where we can 2015-01-22 13:31:31 -05:00
Ludovic Marcotte 74b27a771a Merge to 2.2.14 2015-01-20 08:35:54 -05:00
Ludovic Marcotte d98ff69fbe Version bumps for the release 2015-01-20 08:35:10 -05:00
Ludovic Marcotte daa7ab87d7 Fix cosmetic change when fetching fb info 2015-01-19 13:54:04 -05:00
Ludovic Marcotte 3e59b1ad6e Improved documentation regarding password policies over LDAP 2015-01-16 12:55:38 -05:00
Ludovic Marcotte e45451a9f9 Improved comments over previous commit 2015-01-16 09:18:37 -05:00
Ludovic Marcotte e9e3dd5646 fixed timezone calculation on recurring event 2015-01-15 15:29:02 -05:00
Ludovic Marcotte 16c863d89d Fixed potential issue when handling multiple Add/Change/Delete/Fetch EAS commands (#3057) 2015-01-15 11:55:04 -05:00
Ludovic Marcotte d87056ebfa handle multipart for EAS/ItemOperations 2015-01-12 14:38:55 -05:00
Ludovic Marcotte 135b463e8f Updated the EAS doc 2015-01-12 13:39:06 -05:00
Ludovic Marcotte f4c4f5af62 fixed From's full name over EAS 2015-01-12 09:09:06 -05:00
Ludovic Marcotte 70e45f7843 fixed birthday offset in EAS 2015-01-12 08:40:06 -05:00
Ludovic Marcotte 28e449b050 Updated NEWS file for bugs fixed 2015-01-10 07:55:55 -05:00
Ludovic Marcotte 6b52e9c945 Fix for bug #2960 2015-01-09 09:04:15 -05:00
Ludovic Marcotte 1cfbea69c1 Make sure we always release local pool 2015-01-08 15:56:16 -05:00
Ludovic Marcotte cb9118d869 Moved the pool destruction at the correct location 2015-01-07 09:29:31 -05:00
Francis Lachapelle dd6dd7251c Fix selection of calendar in event/task editors
Fixes #3049
Fixes #3050
2015-01-06 13:59:20 -05:00
Ludovic Marcotte 24c6c8c91d Fix for bug #3054 2015-01-06 10:59:56 -05:00
Ludovic Marcotte b1ac7a0cca MultipleBookingsFieldName can be set to -1 2015-01-05 13:49:28 -05:00
Francis Lachapelle 59e6d6df4a Fix selection of calendar in event/task editors
Fixes #3049
Fixes #3050
2015-01-05 10:21:37 -05:00
Ludovic Marcotte 2ae326c41f Merge to 2.2.13 2014-12-30 08:01:52 -05:00
Ludovic Marcotte 71ad5de910 Bumped everything for the release 2014-12-30 08:00:41 -05:00
Ludovic Marcotte ead665de85 fix tz issue when the user one was different from the system one with EAS 2014-12-29 16:19:10 -05:00
Ludovic Marcotte a0c1ce8f3b Improved handling of non-existant vs. subscribed folders over EAS 2014-12-29 12:43:20 -05:00
Ludovic Marcotte 204a62aa6a Improved comments in the code 2014-12-23 10:25:53 -05:00
Ludovic Marcotte 31cffdffd3 Fix freebusy info not always returned 2014-12-23 10:24:16 -05:00
Ludovic Marcotte 255bcbe92f Fixed memory leaks in SOGoSyncCacheObject and correctly kill the cache upon each EAS iteration 2014-12-22 19:59:33 -05:00
Ludovic Marcotte 72732879fa Added memory statistics - set SOGoDebugLeaks = YES and call [[self class] memoryStatistics] 2014-12-22 19:32:17 -05:00
Ludovic Marcotte 24a934275f Fix small memory leak incase of errors 2014-12-22 16:12:26 -05:00
Ludovic Marcotte 58f634bffe Cosmetic improvements to the code 2014-12-22 15:26:22 -05:00
Ludovic Marcotte ca4a754f2c Use the right cutoff date 2014-12-22 12:39:58 -05:00
Ludovic Marcotte 8015688df3 Added SOGoMaximumSyncResponseSize to support memory-limited EAS syncs 2014-12-22 11:50:51 -05:00
Ludovic Marcotte b07913d66d See NEWS file 2014-12-22 08:36:55 -05:00
extrafu 6b49a8a341 Merge pull request #68 from Crosenhain/master
Change ACL modification text to non-gender specific terms
2014-12-20 08:29:01 -05:00
Ludovic Marcotte 562d3db1a6 Merge to 2.2.12a 2014-12-19 09:04:01 -05:00
Ludovic Marcotte df8a0d8715 Update ChangeLog 2014-12-19 09:03:37 -05:00
Ludovic Marcotte e6cc56dca1 Bumped version to 2.2.12a 2014-12-19 09:03:19 -05:00
Ludovic Marcotte de3d38262b Fix for bug #3034 2014-12-19 09:01:39 -05:00
Chris Rosenhain 0e56527e05 Change ACL modification text to non-gender specific terms 2014-12-19 11:04:05 +10:30
105 changed files with 2801 additions and 451 deletions

No files matched your search

+4 -2
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
@@ -193,11 +194,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [self note]))
{
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
@@ -229,7 +231,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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]];
}
//
+5 -4
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSString.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSObject+Logs.h>
#include <wbxml/wbxml.h>
#include <wbxml/wbxml_conv.h>
@@ -48,7 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
NSLog(@"Original data written to: %@", path);
[self errorWithFormat: @"Original data written to: %@", path];
}
//
@@ -81,7 +82,7 @@ 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;
}
@@ -114,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;
}
@@ -129,7 +130,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 errorWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
+8 -3
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSTimeZone.h>
#include <SOGo/NSString+Utilities.h>
#include <SOGo/NSData+Crypto.h>
@@ -127,13 +128,17 @@ static NSArray *easCommandParameters = nil;
//
- (NSCalendarDate *) calendarDate
{
NSString *s;
id o;
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y%m%dT%H%M%SZ"];
// We force parsing in the GMT timezone. If we don't do that, the date will be parsed
// in the default timezone.
s = [NSString stringWithFormat: @"%@ GMT", self];
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y%m%dT%H%M%SZ %Z"];
if (!o)
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ"];
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ %Z"];
return o;
}
+1 -1
View File
@@ -4,7 +4,7 @@ to negotiate the fees associated to your user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
http://www.microsoft.com/en-us/legal/intellectualproperty/
and send an email to iplicreq@microsoft.com
+105 -49
View File
@@ -57,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>
@@ -287,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();
}
}
@@ -531,6 +531,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) processSyncGetChanges: (id <DOMElement>) theDocumentElement
inCollection: (id) theCollection
withWindowSize: (unsigned int) theWindowSize
withMaxSyncResponseSize: (unsigned int) theMaxSyncResponseSize
withSyncKey: (NSString *) theSyncKey
withFolderType: (SOGoMicrosoftActiveSyncFolderType) theFolderType
withFilterType: (NSCalendarDate *) theFilterType
@@ -562,7 +563,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dateCache = [folderMetadata objectForKey: @"DateCache"];
if ((theFolderType == ActiveSyncMailFolder || theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder) &&
!([folderMetadata objectForKey: @"MoreAvailable"]) && // previous sync operation reached the windowSize
!([folderMetadata objectForKey: @"MoreAvailable"]) && // previous sync operation reached the windowSize or maximumSyncReponseSize
!([theSyncKey isEqualToString: @"-1"]) && // new sync operation
theFilterType)
{
@@ -590,7 +591,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
softdelete_count++;
}
if (softdelete_count >= theWindowSize)
if (softdelete_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
{
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
@@ -653,7 +654,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pool = [[NSAutoreleasePool alloc] init];
// Check for the WindowSize and slice accordingly
if (return_count >= theWindowSize)
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
{
more_available = YES;
@@ -668,7 +669,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
deleted = [[component objectForKey: @"c_deleted"] intValue];
if (!deleted && ![[component objectForKey: @"c_component"] isEqualToString: component_name])
continue;
{
DESTROY(pool);
continue;
}
uid = [[component objectForKey: @"c_name"] sanitizedServerIdWithType: theFolderType];
@@ -692,10 +696,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (![syncCache objectForKey: uid])
updated = NO;
else if ([[component objectForKey: @"c_lastmodified"] intValue] == [[syncCache objectForKey: uid] intValue])
continue;
{
DESTROY(pool);
continue;
}
return_count++;
sogoObject = [theCollection lookupName: [uid sanitizedServerIdWithType: theFolderType]
inContext: context
acquire: 0];
@@ -705,7 +712,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
componentObject = [sogoObject component: NO secure: NO];
//
// We do NOT synchronize NEW events that are in fact, invitations
// to events. This is due to the fact that Outlook 2013 creates
@@ -727,22 +733,34 @@ 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
{
// no need to set dateCache for Contacts
if ((theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder))
[dateCache setObject: [componentObject startDate] ? [componentObject startDate] : [NSCalendarDate date] forKey: uid]; // FIXME: need to set proper date for recurring events - softDelete
[s appendString: @"<Add xmlns=\"AirSync:\">"];
}
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
@@ -757,10 +775,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @"</Add>"];
return_count++;
DESTROY(pool);
}
} // for ...
DESTROY(pool);
} // for (i = 0; i < max; i++) ...
if (more_available)
{
@@ -791,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];
@@ -829,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
@@ -847,7 +863,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pool = [[NSAutoreleasePool alloc] init];
// Check for the WindowSize and slice accordingly
if (return_count >= theWindowSize)
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
{
NSString *lastSequence;
more_available = YES;
@@ -1003,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];
@@ -1012,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];
@@ -1021,7 +1037,7 @@ 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];
@@ -1030,7 +1046,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if ([[element tagName] isEqualToString: @"Fetch"])
{
// Fetch
[self processSyncFetchCommand: aCommand
[self processSyncFetchCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@@ -1047,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, status;
NSMutableDictionary *folderMetadata;
changeBuffer = [NSMutableString string];
commandsBuffer = [NSMutableString string];
@@ -1076,7 +1094,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//[theBuffer appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
//[theBuffer appendFormat: @"<Status>%d</Status>", 8];
//[theBuffer appendString: @"</Collection>"];
return;
}
@@ -1139,6 +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]]
@@ -1169,6 +1187,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[commandsBuffer appendFormat: @"<Responses>%@</Responses>", 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])
@@ -1179,7 +1199,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
// 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 = [[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"SyncKey"];
davCollectionTag = [folderMetadata objectForKey: @"SyncKey"];
if (!davCollectionTag)
davCollectionTag = [collection davCollectionTag];
@@ -1189,8 +1209,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
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
@@ -1211,7 +1236,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 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 ([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"MoreAvailable"])
if ([folderMetadata objectForKey: @"MoreAvailable"])
[theBuffer appendString: @"<MoreAvailable/>"];
[theBuffer appendString: commandsBuffer];
@@ -1324,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 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)
{
@@ -1355,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];
@@ -1363,36 +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];
d = [d xml2wbxml];
[theResponse setContent: d];
}
// Avoid overloading the autorelease pool here, as Sync command can
// generate fairly large responses.
d = [output dataUsingEncoding: NSUTF8StringEncoding];
RELEASE(output);
d = [d xml2wbxml];
[theResponse setContent: d];
}
@end
+179 -74
View File
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoPermissions.h>
@@ -58,6 +59,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NGCalendarDateRange.h>
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NGImap4Client.h>
@@ -793,10 +795,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
cKey = [allKeys objectAtIndex: i];
// ignore invalid folder in cache caused by fs code bugs
if ([cKey isEqualToString:@"(null)"])
continue;
// if a cache entry is not found in imapGUIDs its either an imap which has been deleted or its an other folder type which can be checked via lookupName.
if (![imapGUIDs allKeysForObject: cKey])
{
@@ -807,7 +805,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[o setTableUrl: [self folderTableURL]];
[o reloadIfNeeded];
if ([cKey hasPrefix: @"folder"])
if ([cKey hasPrefix: @"folder"] || [cKey isEqualToString:@"(null)"])
{
[commands appendFormat: @"<Delete><ServerId>%@</ServerId></Delete>", [[NSString stringWithFormat: @"mail/%@", [cKey substringFromIndex: 6]] stringByEscapingURL]] ;
command_count++;
@@ -849,6 +847,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
folderMetadata = [allFoldersMetadata objectAtIndex: i];
nameInCache = [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]];
// we have no guid - ignore the folder
if (![imapGUIDs objectForKey: nameInCache])
continue;
serverId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: nameInCache] substringFromIndex: 6]];
name = [folderMetadata objectForKey: @"displayName"];
@@ -1214,71 +1217,136 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
NSString *fileReference, *realCollectionId;
NSMutableString *s;
NSArray *fetchRequests;
id aFetch;
int i;
SOGoMicrosoftActiveSyncFolderType folderType;
fileReference = [[[(id)[theDocumentElement getElementsByTagName: @"FileReference"] lastObject] textValue] stringByUnescapingURL];
s = [NSMutableString string];
realCollectionId = [fileReference realCollectionIdWithFolderType: &folderType];
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
[s appendString: @"<ItemOperations xmlns=\"ItemOperations:\">"];
[s appendString: @"<Status>1</Status>"];
[s appendString: @"<Response>"];
fetchRequests = (id)[theDocumentElement getElementsByTagName: @"Fetch"];
if (folderType == ActiveSyncMailFolder)
if ([fetchRequests count])
{
id currentFolder, currentCollection, currentBodyPart;
NSString *folderName, *messageName, *pathToPart;
SOGoMailAccounts *accountsFolder;
SOGoUserFolder *userFolder;
SOGoMailObject *mailObject;
NSMutableData *bytes, *parts;
NSMutableArray *partLength;
NSData *d;
NSRange r1, r2;
bytes = [NSMutableData data];
parts = [NSMutableData data];
partLength = [NSMutableArray array];
r1 = [realCollectionId rangeOfString: @"/"];
r2 = [realCollectionId rangeOfString: @"/" options: 0 range: NSMakeRange(NSMaxRange(r1)+1, [realCollectionId length]-NSMaxRange(r1)-1)];
for (i = 0; i < [fetchRequests count]; i++)
{
aFetch = [fetchRequests objectAtIndex: i];
fileReference = [[[(id)[aFetch getElementsByTagName: @"FileReference"] lastObject] textValue] stringByUnescapingURL];
realCollectionId = [fileReference realCollectionIdWithFolderType: &folderType];
if (folderType == ActiveSyncMailFolder)
{
id currentFolder, currentCollection, currentBodyPart;
NSString *folderName, *messageName, *pathToPart;
SOGoMailAccounts *accountsFolder;
SOGoUserFolder *userFolder;
SOGoMailObject *mailObject;
NSRange r1, r2;
r1 = [realCollectionId rangeOfString: @"/"];
r2 = [realCollectionId rangeOfString: @"/" options: 0 range: NSMakeRange(NSMaxRange(r1)+1, [realCollectionId length]-NSMaxRange(r1)-1)];
folderName = [realCollectionId substringToIndex: r1.location];
messageName = [realCollectionId substringWithRange: NSMakeRange(NSMaxRange(r1), r2.location-r1.location-1)];
pathToPart = [realCollectionId substringFromIndex: r2.location+1];
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
folderName = [realCollectionId substringToIndex: r1.location];
messageName = [realCollectionId substringWithRange: NSMakeRange(NSMaxRange(r1), r2.location-r1.location-1)];
pathToPart = [realCollectionId substringFromIndex: r2.location+1];
currentCollection = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", folderName]
inContext: context
acquire: NO];
mailObject = [currentCollection lookupName: messageName inContext: context acquire: NO];
currentBodyPart = [mailObject lookupImap4BodyPartKey: pathToPart inContext: context];
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
currentCollection = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", folderName]
inContext: context
acquire: NO];
s = [NSMutableString string];
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
[s appendString: @"<ItemOperations xmlns=\"ItemOperations:\">"];
[s appendString: @"<Status>1</Status>"];
[s appendString: @"<Response>"];
mailObject = [currentCollection lookupName: messageName inContext: context acquire: NO];
currentBodyPart = [mailObject lookupImap4BodyPartKey: pathToPart inContext: context];
[s appendString: @"<Fetch>"];
[s appendString: @"<Status>1</Status>"];
[s appendFormat: @"<FileReference xmlns=\"AirSyncBase:\">%@</FileReference>", [fileReference stringByEscapingURL]];
[s appendString: @"<Properties>"];
[s appendString: @"<Fetch>"];
[s appendString: @"<Status>1</Status>"];
[s appendFormat: @"<FileReference xmlns=\"AirSyncBase:\">%@</FileReference>", [fileReference stringByEscapingURL]];
[s appendString: @"<Properties>"];
[s appendFormat: @"<ContentType xmlns=\"AirSyncBase:\">%@/%@</ContentType>", [[currentBodyPart partInfo] objectForKey: @"type"], [[currentBodyPart partInfo] objectForKey: @"subtype"]];
[s appendFormat: @"<Data>%@</Data>", [[currentBodyPart fetchBLOB] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<ContentType xmlns=\"AirSyncBase:\">%@/%@</ContentType>", [[currentBodyPart partInfo] objectForKey: @"type"], [[currentBodyPart partInfo] objectForKey: @"subtype"]];
[s appendString: @"</Properties>"];
[s appendString: @"</Fetch>"];
if ([[theResponse headerForKey: @"Content-Type"] isEqualToString:@"application/vnd.ms-sync.multipart"])
{
[s appendFormat: @"<Part>%d</Part>", i+1];
[partLength addObject: [NSNumber numberWithInteger: [[currentBodyPart fetchBLOB] length]]];
[parts appendData:[currentBodyPart fetchBLOB]];
}
else
{
[s appendFormat: @"<Range>0-%d</Range>", [[[currentBodyPart fetchBLOB] activeSyncRepresentationInContext: context] length]-1];
[s appendFormat: @"<Data>%@</Data>", [[currentBodyPart fetchBLOB] activeSyncRepresentationInContext: context]];
}
[s appendString: @"</Properties>"];
[s appendString: @"</Fetch>"];
}
else
{
[theResponse setStatus: 500];
return;
}
}
[s appendString: @"</Response>"];
[s appendString: @"</ItemOperations>"];
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
[theResponse setContent: d];
}
else
{
[theResponse setStatus: 500];
if ([[theResponse headerForKey: @"Content-Type"] isEqualToString:@"application/vnd.ms-sync.multipart"])
{
uint32_t PartCount;
uint32_t Offset;
uint32_t Len;
// 2.2.2.9.1.1 - MultiPartResponse -- http://msdn.microsoft.com/en-us/library/jj663270%28v=exchg.80%29.aspx
PartCount = [partLength count] + 1;
Offset = ((PartCount) * 2) * 4 + 4;
Len = [d length];
[bytes appendBytes: &PartCount length: 4];
[bytes appendBytes: &Offset length: 4];
[bytes appendBytes: &Len length: 4];
// 2.2.2.9.1.1.1 - PartMetaData -- http://msdn.microsoft.com/en-us/library/jj663267%28v=exchg.80%29.aspx
for (i = 0; i < [fetchRequests count]; i++)
{
Offset = Offset + Len;
Len = [[partLength objectAtIndex:i] intValue];
[bytes appendBytes: &Offset length: 4];
[bytes appendBytes: &Len length: 4];
}
// First part - webxml
[bytes appendData: d];
// Subsequent parts - requested data
[bytes appendData: parts];
[theResponse setContent: bytes];
}
else
{
[theResponse setContent: d];
}
}
}
@@ -1738,30 +1806,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// We build the list of folders to "ping". When the payload is empty, we use the list
// of "cached" folders.
allCollections = (id)[theDocumentElement getElementsByTagName: @"Folders"];
allCollections = (id)[theDocumentElement getElementsByTagName: @"Folder"];
allFoldersID = [NSMutableArray array];
if (![allCollections count])
{
SOGoMailAccounts *accountsFolder;
SOGoMailAccount *accountFolder;
SOGoUserFolder *userFolder;
NSArray *allValues;
// We received an empty Ping request. Return status '3' to ask client to resend the request with complete body.
s = [NSMutableString string];
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
[s appendString: @"<Ping xmlns=\"Ping:\">"];
[s appendString: @"<Status>3</Status>"];
[s appendString: @"</Ping>"];
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
allValues = [[accountFolder imapFolderGUIDs] allValues];
for (i = 0; i < [allValues count]; i++)
[allFoldersID addObject: [NSString stringWithFormat: @"mail/%@", [[allValues objectAtIndex: i] substringFromIndex: 6]]];
[theResponse setContent: d];
// FIXME: handle multiple GCS collecitons
[allFoldersID addObject: @"vcard/personal"];
[allFoldersID addObject: @"vevent/personal"];
[allFoldersID addObject: @"vtodo/personal"];
return;
}
else
{
@@ -1805,13 +1867,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ([foldersWithChanges count])
{
NSLog(@"Change detected, we push the content.");
[self logWithFormat: @"Change detected, we push the content."];
status = 2;
break;
}
else
{
NSLog(@"Sleeping %d seconds while detecting changes...", internalInterval);
[self logWithFormat: @"Sleeping %d seconds while detecting changes...", internalInterval];
sleep(internalInterval);
}
}
@@ -2158,6 +2220,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NGMimeMessage *message;
NSException *error;
NSData *data;
NGMutableHashMap *map;
NGMimeMessage *messageToSend;
NGMimeMessageGenerator *generator;
NSDictionary *identity;
NSString *fullName, *email;
// We get the mail's data
data = [[[[(id)[theDocumentElement getElementsByTagName: @"MIME"] lastObject] textValue] stringByDecodingBase64] dataUsingEncoding: NSUTF8StringEncoding];
@@ -2166,6 +2233,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
parser = [[NGMimeMessageParser alloc] init];
message = [parser parsePartFromData: data];
RELEASE(parser);
map = [NGHashMap hashMapWithDictionary: [message headers]];
identity = [[context activeUser] primaryIdentity];
fullName = [identity objectForKey: @"fullName"];
email = [identity objectForKey: @"email"];
if ([fullName length])
[map setObject: [NSString stringWithFormat: @"%@ <%@>", fullName, email] forKey: @"from"];
else
[map setObject: email forKey: @"from"];
messageToSend = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
[messageToSend setBody: [message body]];
generator = [[[NGMimeMessageGenerator alloc] init] autorelease];
data = [generator generateMimeFromPart: messageToSend];
error = [self _sendMail: data
recipients: [message allRecipients]
@@ -2294,6 +2379,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSException *error;
id body, bodyFromSmartForward;
NSString *fullName, *email;
NSDictionary *identity;
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
@@ -2317,6 +2404,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
map = [NGHashMap hashMapWithDictionary: [messageFromSmartForward headers]];
[map setObject: @"multipart/mixed" forKey: @"content-type"];
identity = [[context activeUser] primaryIdentity];
fullName = [identity objectForKey: @"fullName"];
email = [identity objectForKey: @"email"];
if ([fullName length])
[map setObject: [NSString stringWithFormat: @"%@ <%@>", fullName, email] forKey: @"from"];
else
[map setObject: email forKey: @"from"];
messageToSend = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
body = [[[NGMimeMultipartBody alloc] initWithPart: messageToSend] autorelease];
@@ -2480,8 +2576,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
// We check if it's a Ping command with no body.
// See http://msdn.microsoft.com/en-us/library/ee200913(v=exchg.80).aspx for details
if ([cmdName caseInsensitiveCompare: @"Ping"] != NSOrderedSame && [cmdName caseInsensitiveCompare: @"GetAttachment"] != NSOrderedSame)
return [NSException exceptionWithHTTPStatus: 500];
if ([cmdName caseInsensitiveCompare: @"Ping"] != NSOrderedSame && [cmdName caseInsensitiveCompare: @"GetAttachment"] != NSOrderedSame && [cmdName caseInsensitiveCompare: @"Sync"] != NSOrderedSame)
{
RELEASE(context);
RELEASE(pool);
return [NSException exceptionWithHTTPStatus: 500];
}
}
if (d)
@@ -2499,19 +2599,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Ping or Sync command with empty body
cmdName = [NSString stringWithFormat: @"process%@:inResponse:", cmdName];
}
aSelector = NSSelectorFromString(cmdName);
// The -processItemOperations: method will generate a multipart response when Content-Type is application/vnd.ms-sync.multipart
if ([[theRequest headerForKey: @"MS-ASAcceptMultiPart"] isEqualToString:@"T"])
[theResponse setHeader: @"application/vnd.ms-sync.multipart" forKey: @"Content-Type"];
else
[theResponse setHeader: @"application/vnd.ms-sync.wbxml" forKey: @"Content-Type"];
[self performSelector: aSelector withObject: documentElement withObject: theResponse];
[theResponse setHeader: @"application/vnd.ms-sync.wbxml" forKey: @"Content-Type"];
[theResponse setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
[theResponse setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
[theResponse setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
[theResponse setHeader: @"2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
RELEASE(context);
RELEASE(pool);
return nil;
}
+117 -6
View File
@@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSString+Encoding.h>
#import <NGImap4/NGImap4Envelope.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGImap4/NSString+Imap4.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGMime/NGMimeBodyPart.h>
@@ -57,6 +58,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <Mailer/SOGoMailLabel.h>
#import <SOGo/SOGoUserDefaults.h>
#include "iCalTimeZone+ActiveSync.h"
#include "NSData+ActiveSync.h"
#include "NSDate+ActiveSync.h"
@@ -204,6 +209,7 @@ struct GlobalObjectId {
//
//
- (NSData *) _preferredBodyDataInMultipartUsingType: (int) theType
nativeTypeFound: (int *) theNativeTypeFound
{
NSString *encoding, *key, *plainKey, *htmlKey, *type, *subtype;
NSDictionary *textParts, *part;
@@ -222,6 +228,10 @@ struct GlobalObjectId {
type = [part valueForKey: @"type"];
subtype = [part valueForKey: @"subtype"];
// Don't select an attachment as body
if ([[[part valueForKey: @"disposition"] valueForKey: @"type"] isEqualToString: @"attachment"])
continue;
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"html"])
htmlKey = key;
else if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"plain"])
@@ -229,11 +239,22 @@ struct GlobalObjectId {
}
key = nil;
*theNativeTypeFound = 1;
if (theType == 2)
key = htmlKey;
else if (theType == 1)
if (theType == 2 && htmlKey)
{
key = htmlKey;
*theNativeTypeFound = 2;
}
else if (theType == 1 && plainKey)
key = plainKey;
else if (theType == 2 && plainKey)
key = plainKey;
else if (theType == 1 && htmlKey)
{
key = htmlKey;
*theNativeTypeFound = 2;
}
if (key)
{
@@ -254,6 +275,10 @@ struct GlobalObjectId {
charset = @"us-ascii";
s = [NSString stringWithData: d usingEncodingNamed: charset];
if (theType == 1 && *theNativeTypeFound == 2)
s = [s htmlToText];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
@@ -434,12 +459,12 @@ struct GlobalObjectId {
{
s = [s htmlToText];
}
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
else if ([type isEqualToString: @"multipart"])
{
d = [self _preferredBodyDataInMultipartUsingType: theType];
d = [self _preferredBodyDataInMultipartUsingType: theType nativeTypeFound: theNativeType];
}
}
else if (theType == 4)
@@ -729,7 +754,13 @@ struct GlobalObjectId {
len = [content length];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
// 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>"];
@@ -774,6 +805,27 @@ struct GlobalObjectId {
[s appendString: @"<Flag xmlns=\"Email:\">"];
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", ([self flagged] ? 2 : 0)];
[s appendString: @"</Flag>"];
// Categroies/Labels
NSEnumerator *categories;
categories = [[[self fetchCoreInfos] objectForKey: @"flags"] objectEnumerator];
if (categories)
{
NSString *currentFlag;
NSDictionary *v;
v = [[[context activeUser] userDefaults] mailLabelsColors];
[s appendFormat: @"<Categories xmlns=\"Email:\">"];
while ((currentFlag = [categories nextObject]))
{
if ([[v objectForKey: currentFlag] objectAtIndex:0])
[s appendFormat: @"<Category>%@</Category>", [[[v objectForKey: currentFlag] objectAtIndex:0] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
// FIXME - support these in the future
//[s appendString: @"<ConversationId xmlns=\"Email2:\">foobar</ConversationId>"];
@@ -836,6 +888,65 @@ struct GlobalObjectId {
else
[self removeFlags: @"seen"];;
}
if ((o = [theValues objectForKey: @"Categories"]))
{
NSEnumerator *categories;
NSString *currentFlag;
NSDictionary *v;
v = [[[context activeUser] userDefaults] mailLabelsColors];
// add categories/labels sent from client
if ([o isKindOfClass: [NSArray class]])
{
NSEnumerator *enumerator;
NSMutableArray *labels;
NSEnumerator *flags;
id key;
labels = [NSMutableArray array];
enumerator = [v keyEnumerator];
flags = [o objectEnumerator];
while ((currentFlag = [flags nextObject]))
{
while ((key = [enumerator nextObject]))
{
if (([currentFlag isEqualToString:[[v objectForKey:key] objectAtIndex:0]]))
{
[labels addObject: key];
break;
}
}
}
[self addFlags: [labels componentsJoinedByString: @" "]];
}
categories = [[[self fetchCoreInfos] objectForKey: @"flags"] objectEnumerator];
// remove all categories/labels from server which were not it the list sent from client
if (categories)
{
while ((currentFlag = [categories nextObject]))
{
// only deal with lables and don't touch flags like seen and flagged
if (([v objectForKey: currentFlag]))
{
if (![o isKindOfClass: [NSArray class]])
{
[self removeFlags: currentFlag];
}
else if (([o indexOfObject: [[v objectForKey:currentFlag] objectAtIndex:0]] == NSNotFound))
{
[self removeFlags: currentFlag];
}
}
}
}
}
}
@end
+1 -1
View File
@@ -55,7 +55,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[o setUID: theUID];
[o setSequence: theSequence];
return o;
return [o autorelease];
}
- (void) dealloc
@@ -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"];
}
+11 -23
View File
@@ -332,7 +332,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
iCalTimeZone *tz;
id o;
NSInteger tzOffset;
BOOL isAllDay;
if ((o = [theValues objectForKey: @"UID"]))
@@ -384,10 +383,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Some Windows devices don't send during event updates.
//if ((o = [theValues objectForKey: @"TimeZone"]))
// {
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
//}
// }
//else
{
// We haven't received a timezone, let's use the user's timezone
// specified in SOGo for now.
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
}
// FIXME: merge with iCalToDo
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
@@ -402,21 +406,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[start setTimeZone: tz];
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
if (isAllDay)
{
[start setDate: o];
[start setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDateTime: o];
}
}
@@ -429,19 +425,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDate: o];
[end setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDateTime: o];
}
}
-12
View File
@@ -143,8 +143,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
iCalTimeZone *tz;
id o;
NSInteger tzOffset;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
@@ -165,10 +163,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
o = [o calendarDate];
completed = (iCalDateTime *) [self uniqueChildWithTag: @"completed"];
//tzOffset = [[o timeZone] secondsFromGMTForDate: o];
//o = [o dateByAddingYears: 0 months: 0 days: 0
// hours: 0 minutes: 0
// seconds: -tzOffset];
[completed setDate: o];
[self setStatus: @"COMPLETED"];
}
@@ -177,15 +171,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
iCalDateTime *due;
o = [o calendarDate];
due = (iCalDateTime *) [self uniqueChildWithTag: @"due"];
[due setTimeZone: tz];
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[due setDateTime: o];
}
+703
View File
@@ -1,3 +1,706 @@
commit 72b210cd2ebccc8e9cdc13c23abb76b7f455b780
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Feb 12 10:29:46 2015 -0500
Fixed typo
M NEWS
commit a80d75d09cd0b6f310455e33847ae62433e258ca
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Feb 12 10:27:10 2015 -0500
Preparation for the release
M Documentation/docinfo.xml
M Documentation/includes/global-attributes.asciidoc
M NEWS
M Version
commit aae76dc4e6ce1909a1aeaee9500ec65e8e67aec8
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Feb 12 09:57:10 2015 -0500
Limit curl request for webcalendars to 60 seconds
M SoObjects/Appointments/SOGoWebAppointmentFolder.m
commit c20ca0e33dd3e25ba41f7b2a2cd70a1c39d1e125
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Thu Feb 12 09:29:40 2015 -0500
Fix exception in set operation of sogo-tool
M NEWS
M Tools/SOGoToolUserPreferences.m
commit 601a9ca5598490f839938884f20d0a366388ed4b
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Thu Feb 12 09:09:18 2015 -0500
Update translations
M NEWS
M UI/PreferencesUI/Czech.lproj/Localizable.strings
M UI/PreferencesUI/Finnish.lproj/Localizable.strings
M UI/PreferencesUI/French.lproj/Localizable.strings
M UI/PreferencesUI/German.lproj/Localizable.strings
M UI/PreferencesUI/Hungarian.lproj/Localizable.strings
commit d7c283f7511c7753f2cf0fc5af0e2eaea826b66f
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Feb 12 08:49:17 2015 -0500
improved fetching of text parts over EAS
M ActiveSync/SOGoMailObject+ActiveSync.m
M NEWS
commit f3325b8b0d59a730716090b8f5e1319ce3edfd70
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Feb 11 18:13:36 2015 -0500
Updated NEWS file wrt fixes
M NEWS
commit b4ea4d7e9fd90520675452bdcbf70155d6b87eef
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Feb 11 14:39:57 2015 -0500
Improvement over previous commit
M UI/Templates/PreferencesUI/UIxPreferences.wox
M UI/WebServerResources/UIxPreferences.js
commit 9447437d6fd9da2701312363ae92427d2404749a
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Feb 11 14:33:32 2015 -0500
Added missing strings from previous commit
M UI/PreferencesUI/English.lproj/Localizable.strings
commit 322f72626a3253f9d290cfb6d83ff8f5fac2a4e4
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Feb 11 14:30:40 2015 -0500
now possible to limit automatic forwards to internal/external domains
M Documentation/SOGoInstallationGuide.asciidoc
M NEWS
M SoObjects/SOGo/SOGoDomainDefaults.h
M SoObjects/SOGo/SOGoDomainDefaults.m
M UI/PreferencesUI/UIxPreferences.m
M UI/Templates/PreferencesUI/UIxPreferences.wox
M UI/WebServerResources/UIxPreferences.js
commit 55ae4cb8c0390f2007ea08896e1adcb722e72c10
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Feb 11 12:59:04 2015 -0500
First pass at EAS' best practices for SOGo
M Documentation/SOGoInstallationGuide.asciidoc
M NEWS
commit e5d01428ad074d45ed8719b3aaac5d09537faba4
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Feb 11 11:31:35 2015 -0500
now possible for SOGo to change the sambaNTPassword/sambaLMPassword
M Documentation/SOGoInstallationGuide.asciidoc
M NEWS
M SoObjects/SOGo/GNUmakefile
M SoObjects/SOGo/LDAPSource.h
M SoObjects/SOGo/LDAPSource.m
M SoObjects/SOGo/NSData+Crypto.h
M SoObjects/SOGo/NSData+Crypto.m
M SoObjects/SOGo/NSString+Crypto.h
M SoObjects/SOGo/NSString+Crypto.m
A SoObjects/SOGo/lmhash.c
A SoObjects/SOGo/lmhash.h
M Tools/SOGoTool.h
M Tools/SOGoTool.m
commit 82178fd6ceb5c4cb9acb10a4be06c022c895de7a
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Feb 11 08:31:32 2015 -0500
Initial patch from tfu for bug #3055
M ActiveSync/SOGoMailObject+ActiveSync.m
commit 6cf1ec998e33990e77725b9c84bb3ba7ec34dcbc
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Tue Feb 10 07:09:31 2015 -0500
Updated NEWS file for the #3095 bug fix in SOPE
M NEWS
commit 6c9b1a494fa1f0a44b118f6c4a399e958796704d
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Feb 9 16:12:59 2015 -0500
Fix for bug #2332
M NEWS
M SoObjects/SOGo/SOGoSieveManager.m
M UI/PreferencesUI/English.lproj/Localizable.strings
M UI/PreferencesUI/UIxPreferences.m
M UI/Templates/PreferencesUI/UIxPreferences.wox
commit 98e4c8ca55b0424111bd7c98060f689316008572
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Feb 9 09:10:55 2015 -0500
Fixed doc regarder domain vs. system settings
M Documentation/SOGoInstallationGuide.asciidoc
commit 3731819e1565a6198237218dff078047628b1316
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Feb 5 16:21:27 2015 -0500
Added patch from tfu for #2995
M ActiveSync/SOGoMailObject+ActiveSync.m
M Documentation/SOGoInstallationGuide.asciidoc
M NEWS
commit eca22caefc921fa713c2b83e24831f52b397eca7
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Feb 5 11:14:53 2015 -0500
Fix for bug #3078
M NEWS
M UI/MailerUI/UIxMailFolderActions.m
commit 923bcf8ae291f574feb611d80c8b5a861dcb663a
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Feb 5 09:29:29 2015 -0500
Applied patch for #3092
M SOPE/GDLContentStore/GCSChannelManager.m
commit 0b44fa81f4c1ec9c5b812d799bf76399ce240b5b
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Tue Feb 3 13:20:57 2015 -0500
Update NEWS file
M NEWS
commit 776b17ff202c45ff63bfc5144dd0ccc37a2f3e58
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Tue Feb 3 12:06:28 2015 -0500
Fix mail editor when not called from mail module
Fixes #3088
M UI/WebServerResources/UIxMailEditor.js
commit 2aa528dacca6c61d194bd2603cf0ba0d5a436647
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 30 11:08:43 2015 -0500
Preparation for the release
M ChangeLog
M Documentation/docinfo.xml
M Documentation/includes/global-attributes.asciidoc
M Version
commit d1d398091961f5d497b67313e098a8a5624089f4
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Fri Jan 30 11:03:38 2015 -0500
Update translations
M NEWS
M UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
M UI/PreferencesUI/Hungarian.lproj/Localizable.strings
commit cf35eec1f5c56d8c7332bed34e2195a8ad9c9e9f
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 30 10:28:45 2015 -0500
Improved the NEWS file for the release
M NEWS
commit 58a0b0c173616db9a3a1592b437dba7e40475321
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 30 10:23:04 2015 -0500
Updated for the release
M NEWS
commit 723a9d4e080644a7a8cef60de9b7450621f0964e
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Jan 29 16:21:06 2015 -0500
Reverted bug fix from #3054 and added comment
M SoObjects/SOGo/SOGoParentFolder.m
commit 4cc158043eb6183ecefed7abd93b579afbdfd7f6
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Wed Jan 28 16:38:27 2015 -0500
Improve CSS server-side cleaner
Fixes #3040
M UI/MailPartViewers/UIxMailPartHTMLViewer.m
commit 7fd1564a86d50cc96995bd3dec44939741312f4a
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Jan 28 15:16:21 2015 -0500
fix for #3076
M ActiveSync/SOGoActiveSyncDispatcher.m
M ActiveSync/SoObjectWebDAVDispatcher+ActiveSync.m
M Documentation/SOGoInstallationGuide.asciidoc
M NEWS
commit 981c718d228f70a23e73d8db913234be7161166c
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Jan 28 15:03:49 2015 -0500
improved handling of EAS Push when no heartbeat is provided
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
M ActiveSync/SOGoActiveSyncDispatcher.m
M NEWS
commit 086361b79a8be7722d8ae476140858067bb06c2a
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 23 16:16:36 2015 -0500
Avoid GNUstep warnings
M SOPE/GDLContentStore/GCSFolderType.m
M UI/MailerUI/UIxMailEditor.m
commit ab12c84887a663c0ec442cfa22b2c9fd1f737f24
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 23 15:32:22 2015 -0500
More NSLog usage cleanups
M SoObjects/Appointments/iCalCalendar+SOGo.m
M SoObjects/Mailer/NSData+Mail.h
M SoObjects/Mailer/NSData+Mail.m
M SoObjects/SOGo/BSONCodec.m
M SoObjects/SOGo/SOGoMailer.m
M SoObjects/SOGo/SOGoSieveManager.m
M SoObjects/SOGo/SOGoWebDAVAclManager.m
commit e2bee230217d16287883fb595d7bfc7ddec0ff77
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Jan 22 16:25:16 2015 -0500
Avoid unnecessary calls to NSLog
M UI/Contacts/UIxListView.m
M UI/MailPartViewers/UIxMailPartHTMLViewer.m
M UI/MailerUI/UIxMailView.m
M UI/Scheduler/UIxCalView.m
M UI/Scheduler/UIxComponentEditor.m
commit 1a10599369da87e64b77cf110624ca6745605585
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Jan 22 15:39:57 2015 -0500
Removed unnecessary NSLog calls
M SOPE/NGCards/CardGroup.m
M SOPE/NGCards/IcalResponse.m
M SOPE/NGCards/NSCalendarDate+ICal.m
M SOPE/NGCards/NSString+NGCards.m
M SOPE/NGCards/iCalObject.m
commit d907d5d268b470c7f461cb0b7951b894e4b77772
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Jan 22 13:31:31 2015 -0500
Avoid using NSLog() where we can
M ActiveSync/NSData+ActiveSync.m
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
M ActiveSync/SOGoActiveSyncDispatcher.m
M Main/SOGo.m
M Main/sogod.m
commit d98ff69fbee723ae268b0cb0836c8dca75394743
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Tue Jan 20 08:35:10 2015 -0500
Version bumps for the release
M ChangeLog
M Documentation/docinfo.xml
M Documentation/includes/global-attributes.asciidoc
M NEWS
M Version
commit daa7ab87d7de8553c4df8790a10f18dead51e61f
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Jan 19 13:54:04 2015 -0500
Fix cosmetic change when fetching fb info
M Documentation/SOGoInstallationGuide.asciidoc
M UI/MainUI/SOGoUserHomePage.m
commit 3e59b1ad6eb4dcca87b75fc478931bb9a404900e
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 16 12:55:38 2015 -0500
Improved documentation regarding password policies over LDAP
M Documentation/SOGoInstallationGuide.asciidoc
commit e45451a9f9a38f869268f4db47e4e24045b63530
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 16 09:18:37 2015 -0500
Improved comments over previous commit
M SOPE/NGCards/iCalTimeZonePeriod.m
commit e9e3dd5646cdf004896f350e35fddd661463f029
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Jan 15 15:29:02 2015 -0500
fixed timezone calculation on recurring event
M NEWS
M SOPE/NGCards/iCalTimeZonePeriod.m
M SoObjects/Appointments/SOGoAppointmentFolder.m
commit 16c863d89dc7555d3c1a490c3467c08c00bd421f
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Jan 15 11:55:04 2015 -0500
Fixed potential issue when handling multiple Add/Change/Delete/Fetch EAS commands (#3057)
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
M NEWS
commit d87056ebfadff870518d032a0fbbd52d5c6d0a88
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Jan 12 14:38:55 2015 -0500
handle multipart for EAS/ItemOperations
M ActiveSync/SOGoActiveSyncDispatcher.m
M NEWS
commit 135b463e8fa770f47aadb58ede53898ce6a8bfdc
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Jan 12 13:39:06 2015 -0500
Updated the EAS doc
M ActiveSync/README
M Documentation/SOGoInstallationGuide.asciidoc
commit f4c4f5af6271956de6a9a339d8834b4f2f66ea45
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Jan 12 09:09:06 2015 -0500
fixed From's full name over EAS
M ActiveSync/SOGoActiveSyncDispatcher.m
M NEWS
commit 70e45f78430e07f75e1fe094f8087902f572fab6
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Jan 12 08:40:06 2015 -0500
fixed birthday offset in EAS
M ActiveSync/NGVCard+ActiveSync.m
M NEWS
commit 28e449b05077b2f0686fae645a84447af1b6d4e8
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Sat Jan 10 07:55:55 2015 -0500
Updated NEWS file for bugs fixed
M NEWS
commit 6b52e9c945af28188b221f4cbf26e0ee28f58195
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Jan 9 09:04:15 2015 -0500
Fix for bug #2960
M NEWS
M SoObjects/SOGo/WOContext+SOGo.h
M SoObjects/SOGo/WOContext+SOGo.m
M SoObjects/SOGo/WORequest+SOGo.h
M SoObjects/SOGo/WORequest+SOGo.m
commit 1cfbea69c14468424f5eb713bcb5918a70b3d676
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Jan 8 15:56:16 2015 -0500
Make sure we always release local pool
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
commit cb9118d869d1d2535c50d46df5457038160de59e
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Wed Jan 7 09:29:31 2015 -0500
Moved the pool destruction at the correct location
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
commit dd6dd7251ca15dc5e758e733e2529003e08e7c7c
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Tue Jan 6 13:59:20 2015 -0500
Fix selection of calendar in event/task editors
Fixes #3049
Fixes #3050
M UI/Scheduler/UIxComponentEditor.m
M UI/Templates/SchedulerUI/UIxAppointmentEditor.wox
M UI/Templates/SchedulerUI/UIxTaskEditor.wox
commit 24c6c8c91d421594bd51f07904d4cd3911cd187c
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Tue Jan 6 10:59:56 2015 -0500
Fix for bug #3054
M NEWS
M SoObjects/Appointments/SOGoAppointmentFolders.m
M SoObjects/SOGo/SOGoFolder.h
M SoObjects/SOGo/SOGoFolder.m
M SoObjects/SOGo/SOGoGCSFolder.h
M SoObjects/SOGo/SOGoObject.h
M SoObjects/SOGo/SOGoObject.m
M SoObjects/SOGo/SOGoParentFolder.h
M SoObjects/SOGo/SOGoParentFolder.m
commit b1ac7a0cca0ace6aecd3ee650e3029ca16709831
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Jan 5 13:49:28 2015 -0500
MultipleBookingsFieldName can be set to -1
M Documentation/SOGoInstallationGuide.asciidoc
M NEWS
M SoObjects/Appointments/SOGoAppointmentObject.m
M SoObjects/SOGo/SOGoUser.m
M SoObjects/SOGo/SOGoUserManager.h
M SoObjects/SOGo/SOGoUserManager.m
M UI/MainUI/SOGoUserHomePage.m
commit 59e6d6df4aa131ca1ea658a212ec1c30e516b5f1
Author: Francis Lachapelle <flachapelle@inverse.ca>
Date: Mon Jan 5 10:12:57 2015 -0500
Fix selection of calendar in event/task editors
Fixes #3049
Fixes #3050
M NEWS
M UI/Templates/SchedulerUI/UIxAppointmentEditor.wox
M UI/Templates/SchedulerUI/UIxTaskEditor.wox
commit 71ad5de910de96a293f75c7c0caba7a36b96c020
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Tue Dec 30 08:00:41 2014 -0500
Bumped everything for the release
M ChangeLog
M Documentation/docinfo.xml
M Documentation/includes/global-attributes.asciidoc
M NEWS
M Version
commit ead665de85e2202dbde926c316cbba927d38dfa7
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 29 16:19:10 2014 -0500
fix tz issue when the user one was different from the system one with EAS
M ActiveSync/NSString+ActiveSync.m
M ActiveSync/iCalEvent+ActiveSync.m
M ActiveSync/iCalToDo+ActiveSync.m
M NEWS
commit a0c1ce8f3b7c22002661d40c24e95a1233b6a6e8
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 29 12:43:20 2014 -0500
Improved handling of non-existant vs. subscribed folders over EAS
M ActiveSync/SOGoActiveSyncDispatcher.m
M SoObjects/Mailer/SOGoMailAccount.m
M SoObjects/Mailer/SOGoMailFolder.m
commit 204a62aa6ac8feb5a13d5a2ee162bb26cc495a50
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Tue Dec 23 10:25:53 2014 -0500
Improved comments in the code
M SoObjects/Appointments/SOGoAppointmentFolder.m
commit 31cffdffd34429d1f4873d07d67e822bff82b7cf
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Tue Dec 23 10:24:16 2014 -0500
Fix freebusy info not always returned
M NEWS
M SoObjects/Appointments/SOGoAppointmentFolder.m
M SoObjects/SOGo/SOGoFolder.h
M SoObjects/SOGo/SOGoFolder.m
commit 255bcbe92fa6b4610edf5f4d05c97b74537ecb6e
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 22 19:59:33 2014 -0500
Fixed memory leaks in SOGoSyncCacheObject and correctly kill the cache upon each EAS iteration
M ActiveSync/SOGoSyncCacheObject.m
M SoObjects/Mailer/SOGoMailBaseObject.m
M SoObjects/SOGo/NSObject+Utilities.m
M UI/MainUI/SOGoMicrosoftActiveSyncActions.m
commit 72732879fafe8ef928593c0cf3e39d962b096ec9
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 22 19:32:17 2014 -0500
Added memory statistics - set SOGoDebugLeaks = YES and call [[self class] memoryStatistics]
M SoObjects/SOGo/NSObject+Utilities.h
M SoObjects/SOGo/NSObject+Utilities.m
commit 24a934275f5678f7ab86cb706aa817dfb5ef8991
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 22 16:12:26 2014 -0500
Fix small memory leak incase of errors
M ActiveSync/SOGoActiveSyncDispatcher.m
commit 58f634bffe35b3a1f6a02072ba0103fea2155a45
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 22 15:26:22 2014 -0500
Cosmetic improvements to the code
M SoObjects/Appointments/SOGoAppointmentObject.m
M SoObjects/SOGo/SOGoMailer.h
M SoObjects/SOGo/SOGoMailer.m
commit ca4a754f2c12784ff437df34c255d3dccbf5c6f2
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 22 12:39:58 2014 -0500
Use the right cutoff date
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
M NEWS
M SoObjects/SOGo/SOGoGCSFolder.m
commit 8015688df31a3e3254093b260851d4664d725ea6
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 22 11:50:51 2014 -0500
Added SOGoMaximumSyncResponseSize to support memory-limited EAS syncs
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
M Documentation/SOGoInstallationGuide.asciidoc
M NEWS
M SoObjects/SOGo/SOGoSystemDefaults.h
M SoObjects/SOGo/SOGoSystemDefaults.m
commit b07913d66d4a47919e09cbcd0c41d92bd97ea0a3
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Mon Dec 22 08:36:55 2014 -0500
See NEWS file
M ActiveSync/NGVCard+ActiveSync.m
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
M ActiveSync/SOGoActiveSyncDispatcher.m
M NEWS
commit df8a0d8715d97873e782ccfbfaab8b580c88c66e
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Dec 19 09:03:37 2014 -0500
Update ChangeLog
M ChangeLog
commit e6cc56dca1126e09cb8336bdbd4e5dabc7b83cf1
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Dec 19 09:03:19 2014 -0500
Bumped version to 2.2.12a
M Version
commit de3d38262b047a1b72ec9a49042059b90e2abc2c
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Fri Dec 19 09:01:39 2014 -0500
Fix for bug #3034
M NEWS
M SoObjects/Mailer/SOGoDraftObject.m
commit 0e56527e05566e78ac8fe4687d19423de78b0276
Author: Chris Rosenhain <chris@rosenha.in>
Date: Fri Dec 19 11:04:05 2014 +1030
Change ACL modification text to non-gender specific terms
M SoObjects/Appointments/SOGoAppointmentObject.m
M SoObjects/Appointments/SOGoCalendarComponent.m
M SoObjects/SOGo/SOGoGCSFolder.m
M SoObjects/SOGo/SOGoUserFolder.h
M UI/MainUI/SOGoRootPage.m
M UI/Templates/SOGoACLDanishModificationAdvisory.wox
M UI/Templates/SOGoACLDanishRemovalAdvisory.wox
M UI/Templates/SOGoACLDutchModificationAdvisory.wox
M UI/Templates/SOGoACLDutchRemovalAdvisory.wox
M UI/Templates/SOGoACLEnglishModificationAdvisory.wox
M UI/Templates/SOGoACLEnglishRemovalAdvisory.wox
commit db911f323d23f263f5fa9c5fb02d8234127687b3
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Dec 18 08:56:23 2014 -0500
Updated ChangeLog and version numbers for the release
M ChangeLog
M Documentation/docinfo.xml
M Documentation/includes/global-attributes.asciidoc
M Version
commit fcddb37a0dd76f75bb16f9380e8b8a01865d0c4c
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
Date: Thu Dec 18 08:53:31 2014 -0500
+124 -20
View File
@@ -911,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
@@ -998,7 +999,17 @@ 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.
|updateSambaNTLMPasswords
|If set to `YES`, SOGo will automatically update the sambaNTPassword
and sambaLMPassword attributes when changing passwords. The attributes
must be called sambaNTPassword and sambaLMPassword. You must also make
sure the correct ACL is set in your LDAP server to allow users to change
their own sambaNTPassword and sambaLMPassword password attributes.
Defaults to `NO` when unset.
|isAddressBook
|If set to `YES`, this LDAP source is used as a shared address book
@@ -1326,27 +1337,27 @@ The following table describes the parameters that were set:
[cols="3,47,50a"]
|=======================================================================
|D |SOGoProfileURL
|S |SOGoProfileURL
|Parameter used to set the database URL so that SOGo can retrieve user
profiles.
For MySQL, set the database URL to something like:
`mysql://sogo:sogo@localhost:3306/sogo/sogo_user_profile`.
|D |OCSFolderInfoURL
|S |OCSFolderInfoURL
|Parameter used to set the database URL so that SOGo can retrieve the
location of user folders (address books and calendars).
For Oracle, set the database URL to something like:
`oracle://sogo:sogo@localhost:1526/sogo/sogo_folder_info`.
|D |OCSSessionsFolderURL
|S |OCSSessionsFolderURL
|Parameter used to set the database URL so that SOGo can store and
retrieve secured user sessions information. For PostgreSQL, the database
URL could be set to something like:
`postgresql://sogo:sogo@localhost:5432/sogo/sogo_sessions_folder`.
|D |OCSEMailAlarmsFolderURL
|S |OCSEMailAlarmsFolderURL
|Parameter used to set the database URL for email-based alarms (that can
be set on events and tasks). This parameter is relevant only if
_SOGoEnableEMailAlarms_ is set to `YES`. For PostgreSQL, the database
@@ -1476,7 +1487,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
@@ -1778,6 +1792,12 @@ host.
Defaults to `NO` when unset.
|D |SOGoForwardConstraints
|Parameter used to set constraints on possible addresses used when
automatically forwarding mails. When set to `0` (default), no constraint
is enforced. When set to `1`, only internal domains can be used. When
set to `2`, only external domains can be used.
|D |SOGoSieveScriptsEnabled
|Parameter used to activate the edition from the preferences windows of
server-side mail filters. Requires Sieve script support on the IMAP
@@ -2340,8 +2360,8 @@ easier. These GUI utilities can make use of templates to create and
pre-configure typical user accounts or any standardized LDAP record,
along with the correct object classes, fields and default values.
Microsoft ActiveSync
--------------------
Microsoft Enterprise ActiveSync
-------------------------------
SOGo supports the Microsoft ActiveSync protocol.
@@ -2390,6 +2410,15 @@ _SOGoMaximumPingInterval_.
If not set, it defaults to `10` seconds.
|S |SOGoMaximumSyncResponseSize
|Parameter used to overwrite the maximum response size during
a Sync operation. The value is in kilobytes. Setting this to 512
means the response size will be of 524288 bytes or less. Note that
if you set the value too low and a mail message (or any other object)
surpasses it, it will still be synced but only this item will be.
Defaults to `0`, which means no overwrite is performed.
|S |SOGoMaximumSyncWindowSize
|Parameter used to overwrite the maximum number of items returned during
a Sync operation.
@@ -2402,24 +2431,22 @@ 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.
* To successfully synchronize Outlook email categories, a corresponding
mail label (Preferences->Mail Options) has to be created manually in SOGo
for each label defined in Outlook. The name in SOGo and in Outlook must be
identical.
* 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.
@@ -2441,13 +2468,90 @@ 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
Inverse inc. provides this software for free, but is not responsible for
anything related to its usage.
Microsoft Enterprise ActiveSync Tuning
--------------------------------------
First of all, it is important to know that most EAS devices will keep
HTTP connections open to SOGo (and thus, Apache) for a long time. This
is required for "push" to work properly. Connections can stay open for
up to one hour, or 3600 seconds.
The first parameter to check is related to Apache's proxying to
SOGo:
----
ProxyPass /Microsoft-Server-ActiveSync \
http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
retry=60 connectiontimeout=5 timeout=360
----
The above line sets a timeout for up to 360 seconds, or 6 minutes. If
you want to let EAS clients keep their HTTP connections open for up
to an hour, you must change the timeout parameter and set it to 3600.
If you change this value, the WOWatchDogRequestTimeout parameter must be changed
accordingly in SOGo's configuration file (/etc/sogo/sogo.conf). By default,
a SOGo child process is allowed to handle a request that can take up
to 10 minutes before it gets killed by its parent process. When using
EAS "push", the client expects to keep its connection open for up to one
hour - so the WOWatchDogRequestTimeout, which is set in minutes,
must be adjusted accordingly.
EAS clients will keep HTTP connections open for a long time
during these two EAS commands: Ping and Sync. By default, SOGo will prevent
EAS clients from keeping connections for a long time. This is to avoid the
situation where all SOGo child processes would be monopolized by EAS clients -
rendering the SOGo web interface or DAV interface unavailable. The
default SOGo behavior is thus similar to disable EAS push entirely.
Two SOGo configuration parameters are available to modify this behavior:
SOGoMaximumPingInterval (set by default to 10 seconds) and
SOGoMaximumSyncInterval (set by default to 30 seconds). If you want
connection to stay open for up to one hour, you should set these
slightly under 3600 seconds (say 3540 - or 59 minutes). During a
long-lived HTTP connection, the SOGo child process will perform
internal polling to detect changes and return them to the EAS client
if any changes are found. The parameter used to control this
is SOGoInternalSyncInterval. By default, polling is done every 10
seconds. This might generate too much load on large-scale system.
The last configuration parameter to adjust is WOWorkersCount - which sets the
number of SOGo child process that will be used to handle requests.
You should have at least one child per EAS device configured to use
"push". You must also have more children than you have EAS devices
configured to use "push" - in order to handle normal SOGo requests to
its Web or DAV interfaces.
Here are some usage examples for EAS devices using "push". In all
cases, the Apache timeout is set to 3600 and the
WOWatchDogRequestTimeout parameter is set to 60.
Example 1 - 100 users, 10 EAS devices:
----
WOWorkersCount = 15;
SOGoMaximumPingInterval = 3540;
SOGoMaximumSyncInterval = 3540;
SOGoInternalSyncInterval = 30;
----
Example 2 - 1000 users, 100 EAS devices:
----
WOWorkersCount = 120;
SOGoMaximumPingInterval = 3540;
SOGoMaximumSyncInterval = 3540;
SOGoInternalSyncInterval = 60;
----
Using SOGo
----------
+3 -3
View File
@@ -1,7 +1,7 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 2.2.12 - December 2014</releaseinfo>
<subtitle>for version 2.2.12</subtitle>
<date>2014-12-18</date>
<releaseinfo>Version 2.2.16 - February 2015</releaseinfo>
<subtitle>for version 2.2.16</subtitle>
<date>2015-02-12</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.12
:release_version: 2.2.16
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
+2 -2
View File
@@ -245,7 +245,7 @@ static BOOL debugLeaks;
}
else
{
NSLog (@"No value specified for '%@'", *urlString);
[self errorWithFormat: @"No value specified for '%@'", *urlString];
ok = NO;
}
}
@@ -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;
+4 -4
View File
@@ -1,15 +1,15 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2009 Inverse inc.
Copyright (C) 2006-2015 Inverse inc.
This file is part of OpenGroupware.org.
This file is part of SOGo.
OGo is free software; you can redistribute it and/or modify it under
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
+71 -3
View File
@@ -1,3 +1,71 @@
2.2.16 (2015-02-12)
-------------------
New features
- now possible for SOGo to change the sambaNTPassword/sambaLMPassword
- now possible to limit automatic forwards to internal/external domains
Enhancements
- added support for email categories using EAS (#2995)
- now possible to always send vacation messages (#2332)
- added EAS best practices to the documentation
- improved fetching of text parts over EAS
- updated Czech, Finnish, French, German and Hungarian translations
Bug fixes
- (regression) fixed sending a message when mail module is not active (#3088)
- mail labels with blanks are not handled correctly (#3078)
- fixed BlackBerry issues sending multiple mails over EAS (#3095)
- fixed plain/text mails showing on one line on Android/EAS (#3055)
- fixed exception in sogo-tool when parsing arguments of a set operation
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)
-------------------
@@ -12,12 +80,12 @@ Enhancements
- updated Czech, Dutch, Finnish, French, German, Polish and Spanish (Spain) translations
Bug fixes
- fix for privacy and categories for EAS (#3022)
- fixed for privacy and categories for EAS (#3022)
- correctly set MeetingStatus for EAS on iOS devices
- Ubuntu Lucid fixes for EAS
- fix calendar reminders for future events (#3008)
- fixed calendar reminders for future events (#3008)
- make sure all text parts are UTF-8 re-encoded for Outlook 2013 over EAS (#3003)
- fix task description truncation affecting WP8 phones over EAS (#3028)
- fixed task description truncation affecting WP8 phones over EAS (#3028)
2.2.11a (2014-12-10)
--------------------
+1 -1
View File
@@ -240,7 +240,7 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60;
handle = currentHandle;
else if (debugPools)
[self logWithFormat: @"DBPOOL: cannot use handle (%@ vs %@) ",
[_url absoluteString], [handle->url absoluteString]];
[_url absoluteString], [currentHandle->url absoluteString]];
return handle;
}
+2 -1
View File
@@ -20,6 +20,7 @@
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
@@ -147,7 +148,7 @@
if ([keys count] == 0)
return folderQualifier;
bindings = [_folder valuesForKeys:keys];
bindings = [_folder dictionaryWithValuesForKeys:keys];
return [folderQualifier qualifierWithBindings:bindings
requiresAllVariables:NO];
}
+6 -4
View File
@@ -59,8 +59,10 @@ static NGCardsSaxHandler *sax = nil;
[parser setErrorHandler:sax];
}
else
NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
__PRETTY_FUNCTION__);
{
//NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
// __PRETTY_FUNCTION__);
}
}
return parser;
@@ -170,8 +172,8 @@ static NGCardsSaxHandler *sax = nil;
{
if (![aChild isKindOfClass: mappedClass])
{
NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
tag, childTag, NSStringFromClass(mappedClass));
//NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
// tag, childTag, NSStringFromClass(mappedClass));
newChild = [aChild elementWithClass: mappedClass];
}
}
+1 -1
View File
@@ -54,7 +54,7 @@
- (BOOL)appendLine:(NSString *)_line {
if (self->isFinished) {
NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
//NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
return NO;
}
// limit length to 75 chars
+2 -2
View File
@@ -77,8 +77,8 @@ static NSString *gmtcalfmt = @"%Y%m%dT%H%M%SZ";
return [self icalStringInGMT];
else {
/* not in GMT */
NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
__PRETTY_FUNCTION__, _tz);
//NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
// __PRETTY_FUNCTION__, _tz);
return [self icalStringInGMT];
}
}
+3 -1
View File
@@ -276,7 +276,9 @@
}
}
else
NSLog(@"Cannot parse iCal duration value: '%@'", self);
{
//NSLog(@"Cannot parse iCal duration value: '%@'", self);
}
if (isNegative)
ti = -ti;
+2 -2
View File
@@ -59,8 +59,8 @@ static NSTimeZone *defTZ = nil;
[self takeValue:_value forXKey:_key];
}
else {
NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
self, NSStringFromClass([self class]), _key);
//NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
// self, NSStringFromClass([self class]), _key);
}
}
+37 -3
View File
@@ -156,13 +156,15 @@
[tzStart setTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [NSCalendarDate dateWithYear: [refDate yearOfCommonEra]
month: [[[rrule byMonth] objectAtIndex: 0] intValue]
day: 1 hour: [tzStart hourOfDay]
day: 1
hour: [tzStart hourOfDay]
minute: [tzStart minuteOfHour] second: 0
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [tmpDate addYear: 0 month: ((pos > 0) ? 0 : 1)
day: 0 hour: 0 minute: 0
second: 0];
/* If the day of the time change is "-XSU", we need to determine whether the
first day of next month is in the same week. In practice, as most time
changes occurs on sundays, it will be false only when that first day is a
@@ -171,10 +173,42 @@
if (dateDayOfWeek > dayOfWeek && pos < 0)
pos++;
/* We check if the days of the week are identical. This is important because if they
are, "pos" actually includes the first day of tmpDate which means we must decrement
pos by 1. This happens for example in the eastern timezone (America/Montreal)
in 2015. We have:
BEGIN:VTIMEZONE
TZID:America/Montreal
X-LIC-LOCATION:America/Montreal
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
The time changes occure on a Sunday, but in March, the 1st is a Sunday itself and in November
the 1st is also a Sunday. If we don't decrement "pos" by one, tmpDate (which is set to March or November 1st
because of "day: 1" will have 14 more days added for March and 7 more days added for November - which will
effectively shift the time change by a whole week.
*/
if (dayOfWeek == dateDayOfWeek)
pos--;
offset = (dayOfWeek - dateDayOfWeek) + (pos * 7);
tmpDate = [tmpDate addYear: 0 month: 0 day: offset
hour: 0 minute: 0 second: 0];
return tmpDate;
}
+24 -13
View File
@@ -492,6 +492,9 @@ static Class iCalEventK = nil;
//
// If the user is NOT the owner of the calendar, by default we exclude the freebusy information.
//
// We must include the freebusy information of other users if we are actually looking at their freebusy information
// but we aren't necessarily subscribed to their calendars.
//
- (BOOL) includeInFreeBusy
{
NSNumber *excludeFromFreeBusy;
@@ -500,16 +503,31 @@ static Class iCalEventK = nil;
userLogin = [[context activeUser] login];
is_owner = [userLogin isEqualToString: [self ownerInContext: context]];
// Check if the owner (not the active user) has excluded the calendar from her/his free busy data.
excludeFromFreeBusy
= [self folderPropertyValueInCategory: @"FreeBusyExclusions"
forUser: [SOGoUser userWithLogin: userLogin]];
if (!excludeFromFreeBusy && !is_owner)
return NO;
return ![excludeFromFreeBusy boolValue];
if ([self isSubscription])
{
// If the user has not yet set an include/not include fb information let's EXCLUDE it.
if (!excludeFromFreeBusy)
return NO;
else
return ![excludeFromFreeBusy boolValue];
}
else if (is_owner)
{
// We are the owner but we haven't included/excluded freebusy info, let's INCLUDE it.
if (!excludeFromFreeBusy)
return YES;
else
return ![excludeFromFreeBusy boolValue];
}
// It's not a subscribtion and we aren't the owner. Let's INCLUDE the freebusy info.
return YES;
}
- (void) setIncludeInFreeBusy: (BOOL) newInclude
@@ -908,11 +926,6 @@ static Class iCalEventK = nil;
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
[record setObject: dateSecs forKey: @"c_enddate"];
// The first instance date is added to the dictionary so it can
// be used by UIxCalListingActions to compute the DST offset.
date = [theFirstCycle startDate];
[record setObject: date forKey: @"cycleStartDate"];
return record;
}
@@ -1085,9 +1098,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
[newRecord setObject: dateSecs forKey: @"c_recurrence_id"];
[newRecord setObject: [NSNumber numberWithInt: 1] forKey: @"c_iscycle"];
// The first instance date is added to the dictionary so it can
// be used by UIxCalListingActions to compute the DST offset.
[newRecord setObject: [fir startDate] forKey: @"cycleStartDate"];
// We identified the record as an exception.
[newRecord setObject: [NSNumber numberWithInt: 1] forKey: @"isException"];
@@ -1,7 +1,7 @@
/* SOGoAppointmentFolders.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* 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
+21 -18
View File
@@ -400,9 +400,9 @@
{
currentUID = [currentAttendee uid];
if (currentUID)
[self _addOrUpdateEvent: newEvent
forUID: currentUID
owner: owner];
[self _addOrUpdateEvent: newEvent
forUID: currentUID
owner: owner];
}
[self sendEMailUsingTemplateNamed: @"Update"
@@ -443,7 +443,7 @@
us = [user userSettings];
moduleSettings = [us objectForKey:@"Calendar"];
// Check if the user prevented his account from beeing invited to events
// Check if the user prevented their account from beeing invited to events
if (![user isResource] && [[moduleSettings objectForKey:@"PreventInvitations"] boolValue])
{
// Check if the user have a whiteList
@@ -637,10 +637,10 @@
if ([fbInfo count])
{
// If we always force the auto-accept if numberOfSimultaneousBookings == 0 (ie., no limit
// If we always force the auto-accept if numberOfSimultaneousBookings <= 0 (ie., no limit
// is imposed) or if numberOfSimultaneousBookings is greater than the number of
// overlapping events
if ([user numberOfSimultaneousBookings] == 0 ||
if ([user numberOfSimultaneousBookings] <= 0 ||
[user numberOfSimultaneousBookings] > [fbInfo count])
{
if (currentAttendee)
@@ -734,7 +734,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
// the modification was actually NOT made on the master event
if ([theEvent recurrenceId])
return;
events = [[theEvent parent] events];
for (i = 0; i < [events count]; i++)
@@ -743,12 +743,12 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
if ([e recurrenceId])
for (j = 0; j < [theAttendees count]; j++)
if (shouldAdd)
[e addToAttendees: [theAttendees objectAtIndex: j]];
else
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
[e addToAttendees: [theAttendees objectAtIndex: j]];
else
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
}
}
//
//
//
@@ -803,14 +803,17 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
// We insert the attendees in all exception occurences, if
// the attendees were added to the master event.
[self _addOrDeleteAttendees: addedAttendees
inRecurrenceExceptionsForEvent: newEvent
add: YES];
inRecurrenceExceptionsForEvent: newEvent
add: YES];
if ([changes sequenceShouldBeIncreased])
{
[newEvent increaseSequence];
// Update attendees calendars and send them an update
// notification by email
// notification by email. We ignore the newly added
// attendees as we don't want to send them invitation
// update emails
[self _handleSequenceUpdateInEvent: newEvent
ignoringAttendees: addedAttendees
fromOldEvent: oldEvent];
@@ -1093,7 +1096,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
else
{
// We must REMOVE any SENT-BY here. This is important since if A accepted
// the event for B and then, B changes by himself his participation status,
// the event for B and then, B changes by theirself their participation status,
// we don't want to keep the previous SENT-BY attribute there.
[(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"];
}
@@ -1191,7 +1194,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
else
{
// We must REMOVE any SENT-BY here. This is important since if A accepted
// the event for B and then, B changes by himself his participation status,
// the event for B and then, B changes by theirself their participation status,
// we don't want to keep the previous SENT-BY attribute there.
[(NSMutableDictionary *)[attendee attributes] removeObjectForKey: @"SENT-BY"];
}
@@ -1208,7 +1211,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
delegatedUID = [otherDelegate uid];
if (delegatedUID)
// Delegate attendee is a local user; remove event from his calendar
// Delegate attendee is a local user; remove event from their calendar
[self _removeEventFromUID: delegatedUID
owner: [theOwnerUser login]
withRecurrenceId: [event recurrenceId]];
@@ -1240,7 +1243,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
[event addToAttendees: delegate];
if (delegatedUID)
// Delegate attendee is a local user; add event to his calendar
// Delegate attendee is a local user; add event to their calendar
[self _addOrUpdateEvent: event
forUID: delegatedUID
owner: [theOwnerUser login]];
@@ -644,8 +644,8 @@
// As much as we can, we try to use c_name == c_uid in order
// to avoid tricky scenarios with some CalDAV clients. For example,
// if Alice invites Bob (both use SOGo) and Bob accepts the invitation
// using Lightning before having refreshed his calendar, he'll end up
// with a duplicate of the event in his database tables.
// using Lightning before having refreshed their calendar, they'll end up
// with a duplicate of the event in their database tables.
if (isNew)
{
newUid = nameInContainer;
@@ -1,6 +1,6 @@
/* SOGoWebAppointmentFolder.m - this file is part of SOGo
*
* Copyright (C) 2009-2014 Inverse inc.
* Copyright (C) 2009-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
@@ -137,6 +137,7 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
curl_easy_setopt (curl, CURLOPT_URL, [location UTF8String]);
curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt (curl, CURLOPT_TIMEOUT, 60L);
authInfos = [self _loadAuthData];
if (authInfos)
+1 -1
View File
@@ -93,7 +93,7 @@
element = [elements objectAtIndex: 0];
else
{
NSLog(@"ERROR: given calendar contains no elements: %@", self);
//NSLog(@"ERROR: given calendar contains no elements: %@", self);
element = nil;
}
+1 -3
View File
@@ -1,8 +1,6 @@
/* NSData+Mail.h - this file is part of SOGo
*
* Copyright (C) 2007 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
+2 -5
View File
@@ -1,9 +1,6 @@
/* NSData+Mail.m - this file is part of SOGo
*
* Copyright (C) 2007-2008 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@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
@@ -52,7 +49,7 @@
else
{
decodedData = nil;
NSLog (@"encoding '%@' unknown, returning nil data", realEncoding);
//NSLog (@"encoding '%@' unknown, returning nil data", realEncoding);
}
}
else
+2 -2
View File
@@ -1217,13 +1217,13 @@ static NSString *userAgent = nil;
if (!isHTML)
{
[map setObject: contentTypeValue forKey: @"content-type"];
[message setHeader: contentTypeValue forKey: @"content-type"];
body = text;
}
else
{
body = [[[NGMimeMultipartBody alloc] initWithPart: message] autorelease];
[map addObject: MultiAlternativeType forKey: @"content-type"];
[message setHeader: MultiAlternativeType forKey: @"content-type"];
// Get the text part from it and add it
[body addBodyPart: [self plainTextBodyPartForText]];
+28 -22
View File
@@ -40,6 +40,7 @@
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Context.h>
#import <NGImap4/NSString+Imap4.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
@@ -667,19 +668,14 @@ static NSString *inboxFolderName = @"INBOX";
NSDictionary *result, *nresult, *namespaceDict;
NSMutableDictionary *folders;
NGImap4Client *client;
SOGoUserDefaults *ud;
NSArray *folderList;
NSEnumerator *e;
NSString *guid;
id object;
BOOL subscribedOnly, hasAnnotatemore;
BOOL hasAnnotatemore;
ud = [[context activeUser] userDefaults];
subscribedOnly = [ud mailShowSubscribedFoldersOnly];
folderList = [[self imap4Connection] allFoldersForURL: [self imap4URL]
onlySubscribedFolders: subscribedOnly];
folderList = [self allFolderPaths];
folders = [NSMutableDictionary dictionary];
@@ -688,19 +684,19 @@ static NSString *inboxFolderName = @"INBOX";
hasAnnotatemore = [self hasCapability: @"annotatemore"];
if (hasAnnotatemore)
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
else
result = [client lstatus: @"*" flags: [NSArray arrayWithObjects: @"x-guid", nil]];
result = [client lstatus: @"*" flags: [NSArray arrayWithObjects: @"x-guid", nil]];
e = [folderList objectEnumerator];
while ((object = [e nextObject]))
{
if (hasAnnotatemore)
guid = [[[[result objectForKey: @"FolderList"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"/comment"] objectForKey: @"value.priv"];
guid = [[[[result objectForKey: @"FolderList"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"/comment"] objectForKey: @"value.priv"];
else
guid = [[[result objectForKey: @"status"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"x-guid"];
guid = [[[result objectForKey: @"status"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"x-guid"];
if (!guid)
{
// Don't generate a GUID for "Other users" and "Shared" namespace folders - user foldername instead
@@ -710,18 +706,28 @@ static NSString *inboxFolderName = @"INBOX";
[folders setObject: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]] forKey: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]]];
continue;
}
guid = [[NSProcessInfo processInfo] globallyUniqueString];
nresult = [client annotation: [object substringFromIndex: 1] entryName: @"/comment" attributeName: @"value.priv" attributeValue: guid];
if (![[nresult objectForKey: @"result"] boolValue])
guid = [NSString stringWithFormat: @"%@", [object substringFromIndex: 1]];
// if folder doesn't exists - ignore it
nresult = [client status: [object substringFromIndex: 1]
flags: [NSArray arrayWithObject: @"UIDVALIDITY"]];
if (![[nresult valueForKey: @"result"] boolValue])
continue;
if (hasAnnotatemore)
{
guid = [[NSProcessInfo processInfo] globallyUniqueString];
nresult = [client annotation: [object substringFromIndex: 1] entryName: @"/comment" attributeName: @"value.priv" attributeValue: guid];
}
// setannotation failed or annotatemore is not available
if (![[nresult objectForKey: @"result"] boolValue] || !hasAnnotatemore)
guid = [NSString stringWithFormat: @"%@", [object substringFromIndex: 1]];
}
[folders setObject: [NSString stringWithFormat: @"folder%@", guid] forKey: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]]];
}
return folders;
}
-4
View File
@@ -43,10 +43,6 @@
@implementation SOGoMailBaseObject
#if 0
static BOOL debugOn = YES;
#endif
- (id) initWithImap4URL: (NSURL *) _url
inContainer: (id) _container
{
+5 -1
View File
@@ -1069,7 +1069,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
NSException *error;
if ([self imap4Connection])
error = [imap4 deleteMailboxAtURL: [self imap4URL]];
{
error = [imap4 deleteMailboxAtURL: [self imap4URL]];
if (!error)
[[imap4 client] unsubscribe: [[self imap4URL] path]];
}
else
error = [NSException exceptionWithName: @"SOGoMailException"
reason: @"IMAP connection is invalid"
+3 -1
View File
@@ -11,6 +11,8 @@
#import <string.h>
#import <objc/objc.h>
#import <NGExtensions/NSObject+Logs.h>
static NSMutableDictionary *timezoneCache = nil;
#define BSONTYPE(tag,className) [className class], [NSNumber numberWithChar: (tag)]
@@ -604,7 +606,7 @@ static NSDictionary *BSONTypes()
if (tz)
[timezoneCache setObject: tz forKey: key];
else
NSLog(@"ERROR: timezone (%@) not found when deserializing BSON data", key);
[self errorWithFormat: @"BSON error: timezone (%@) not found when deserializing BSON data", key];
}
return [NSCalendarDate dateWithYear: year
+3 -3
View File
@@ -77,11 +77,10 @@ SOGo_HEADER_FILES = \
WORequest+SOGo.h \
WOResourceManager+SOGo.h \
WOResponse+SOGo.h \
WOContext+SOGo.h \
WOContext+SOGo.h \
\
SOGoCredentialsFile.h
# daemon tool
all::
@touch SOGoBuild.m
@@ -156,10 +155,11 @@ SOGo_OBJC_FILES = \
WORequest+SOGo.m \
WOResourceManager+SOGo.m \
WOResponse+SOGo.m \
WOContext+SOGo.m \
WOContext+SOGo.m \
\
SOGoCredentialsFile.m
SOGo_C_FILES = lmhash.c
SOGo_RESOURCE_FILES = \
SOGoDefaults.plist \
+2 -1
View File
@@ -1,6 +1,6 @@
/* LDAPSource.h - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* 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
@@ -78,6 +78,7 @@
NSMutableArray *searchAttributes;
BOOL passwordPolicy;
BOOL updateSambaNTLMPasswords;
/* resources handling */
NSString *kindField;
+63 -21
View File
@@ -1,6 +1,6 @@
/* LDAPSource.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* 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
@@ -50,7 +50,6 @@ static Class NSStringK;
stringByReplacingString: @"'" withString: @"\\'"] \
stringByReplacingString: @"%" withString: @"%%"]
@implementation LDAPSource
+ (void) initialize
@@ -113,6 +112,7 @@ static Class NSStringK;
searchAttributes = nil;
passwordPolicy = NO;
updateSambaNTLMPasswords = NO;
kindField = nil;
multipleBookingsField = nil;
@@ -245,6 +245,9 @@ static Class NSStringK;
if ([udSource objectForKey: @"passwordPolicy"])
passwordPolicy = [[udSource objectForKey: @"passwordPolicy"] boolValue];
if ([udSource objectForKey: @"updateSambaNTLMPasswords"])
updateSambaNTLMPasswords = [[udSource objectForKey: @"updateSambaNTLMPasswords"] boolValue];
ASSIGN(MSExchangeHostname, [udSource objectForKey: @"MSExchangeHostname"]);
}
@@ -598,6 +601,40 @@ static Class NSStringK;
return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
}
- (BOOL) _ldapModifyAttribute: (NSString *) theAttribute
withValue: (NSString *) theValue
userDN: (NSString *) theUserDN
password: (NSString *) theUserPassword
connection: (NGLdapConnection *) bindConnection
{
NGLdapModification *mod;
NGLdapAttribute *attr;
NSArray *changes;
BOOL didChange;
attr = [[NGLdapAttribute alloc] initWithAttributeName: theAttribute];
[attr addStringValue: theValue];
mod = [NGLdapModification replaceModification: attr];
changes = [NSArray arrayWithObject: mod];
if ([bindConnection bindWithMethod: @"simple"
binddn: theUserDN
credentials: theUserPassword])
{
didChange = [bindConnection modifyEntryWithDN: theUserDN
changes: changes];
}
else
didChange = NO;
RELEASE(attr);
return didChange;
}
//
//
//
@@ -651,12 +688,8 @@ static Class NSStringK;
{
// We don't use a password policy - we simply use
// a modify-op to change the password
NGLdapModification *mod;
NGLdapAttribute *attr;
NSArray *changes;
NSString* encryptedPass;
attr = [[NGLdapAttribute alloc] initWithAttributeName: @"userPassword"];
if ([_userPasswordAlgorithm isEqualToString: @"none"])
{
encryptedPass = newPassword;
@@ -665,24 +698,33 @@ static Class NSStringK;
{
encryptedPass = [self _encryptPassword: newPassword];
}
if(encryptedPass != nil)
if (encryptedPass != nil)
{
[attr addStringValue: encryptedPass];
mod = [NGLdapModification replaceModification: attr];
changes = [NSArray arrayWithObject: mod];
*perr = PolicyNoError;
if ([bindConnection bindWithMethod: @"simple"
binddn: userDN
credentials: oldPassword])
{
didChange = [bindConnection modifyEntryWithDN: userDN
changes: changes];
}
else
didChange = NO;
didChange = [self _ldapModifyAttribute: @"userPassword"
withValue: encryptedPass
userDN: userDN
password: oldPassword
connection: bindConnection];
}
}
// We must check if we must update the Samba NT/LM password hashes
if (didChange && updateSambaNTLMPasswords)
{
[self _ldapModifyAttribute: @"sambaNTPassword"
withValue: [newPassword asNTHash]
userDN: userDN
password: newPassword
connection: bindConnection];
[self _ldapModifyAttribute: @"sambaLMPassword"
withValue: [newPassword asLMHash]
userDN: userDN
password: newPassword
connection: bindConnection];
}
}
}
}
+4 -2
View File
@@ -1,7 +1,7 @@
/* NSData+Crypto.h - this file is part of SOGo
*
* Copyright (C) 2012 Nicolas Höft
* Copyright (C) 2012 Inverse inc.
* Copyright (C) 2012-2015 Inverse inc.
*
* Author: Nicolas Höft
* Inverse inc.
@@ -32,8 +32,10 @@
@interface NSData (SOGoCryptoExtension)
- (NSData *) asCryptedPassUsingScheme: (NSString *) passwordScheme
withSalt: (NSData *) theSalt;
withSalt: (NSData *) theSalt;
- (NSData *) asLM;
- (NSData *) asMD4;
- (NSData *) asMD5;
- (NSData *) asSMD5UsingSalt: (NSData *) theSalt;
- (NSData *) asSHA1;
+52 -3
View File
@@ -1,7 +1,7 @@
/* NSData+Crypto.m - this file is part of SOGo
*
* Copyright (C) 2012 Nicolas Höft
* Copyright (C) 2012 Inverse inc.
* Copyright (C) 2012-2015 Inverse inc.
* Copyright (C) 2012 Jeroen Dekkers
*
* Author: Nicolas Höft
@@ -39,12 +39,14 @@
#include <stdint.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#define MD4_DIGEST_LENGTH 16
#define MD5_DIGEST_LENGTH 16
#define SHA_DIGEST_LENGTH 20
#define SHA256_DIGEST_LENGTH 32
#define SHA512_DIGEST_LENGTH 64
#elif defined(HAVE_OPENSSL)
#include <openssl/evp.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#else
@@ -145,7 +147,7 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input);
* @return Pseudo-random binary data with length theLength or nil, if an error occured
*/
+ (NSData *) generateSaltForLength: (unsigned int) theLength
withBase64: (BOOL) doBase64
withBase64: (BOOL) doBase64
{
char *buf;
int fd;
@@ -177,7 +179,7 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input);
* @return Binary data from the encryption by the specified scheme. On error the funciton returns nil.
*/
- (NSData *) asCryptedPassUsingScheme: (NSString *) passwordScheme
withSalt: (NSData *) theSalt
withSalt: (NSData *) theSalt
{
if ([passwordScheme caseInsensitiveCompare: @"none"] == NSOrderedSame ||
[passwordScheme caseInsensitiveCompare: @"plain"] == NSOrderedSame ||
@@ -193,6 +195,10 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input);
{
return [self asMD5CryptUsingSalt: theSalt];
}
else if ([passwordScheme caseInsensitiveCompare: @"md4"] == NSOrderedSame)
{
return [self asMD4];
}
else if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
[passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame ||
[passwordScheme caseInsensitiveCompare: @"ldap-md5"] == NSOrderedSame)
@@ -235,6 +241,49 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input);
return nil;
}
- (NSData *) asLM
{
NSData *out;
unsigned char buf[14];
unsigned char *o;
unsigned int len;
memset(buf, 0, 14);
len = ([self length] >= 14 ? 14 : [self length]);
[self getBytes: buf length: len];
o = malloc(16*sizeof(unsigned char));
auth_LMhash(o, buf, len);
out = [NSData dataWithBytes: o length: 16];
free(o);
return out;
}
/**
* Hash the data with MD4. Uses openssl functions to generate it.
*
* @return Binary data from MD4 hashing. On error the funciton returns nil.
*/
- (NSData *) asMD4
{
unsigned char md4[MD4_DIGEST_LENGTH];
memset(md4, 0, MD4_DIGEST_LENGTH);
#if defined(HAVE_GNUTLS)
if (!check_gnutls_init())
return nil;
md4_buffer([self bytes], [self length], md4);
#elif defined(HAVE_OPENSSL)
MD4([self bytes], [self length], md4);
#endif
return [NSData dataWithBytes: md4 length: MD4_DIGEST_LENGTH];
}
/**
* Hash the data with MD5. Uses openssl functions to generate it
+2
View File
@@ -40,6 +40,8 @@
- (NSString *) labelForKey: (NSString *) key
inContext: (WOContext *) context;
+ (void) memoryStatistics;
@end
#endif /* NSOBJECT+UTILITIES_H */
+30
View File
@@ -22,6 +22,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSString.h>
@@ -122,4 +123,33 @@
return label;
}
//
// Set SOGoDebugLeaks = YES in your defaults to enable.
//
+ (void) memoryStatistics
{
Class *classList = GSDebugAllocationClassList ();
Class *pointer;
int i, count, total, peak;
NSString *className;
pointer = classList;
i = 0;
printf("Class count total peak\n");
while (pointer[i] != NULL)
{
className = NSStringFromClass (pointer[i]);
count = GSDebugAllocationCount (pointer[i]);
total = GSDebugAllocationTotal (pointer[i]);
peak = GSDebugAllocationPeak (pointer[i]);
printf("%s %d %d %d\n", [className UTF8String], count, total, peak);
i++;
}
NSZoneFree(NSDefaultMallocZone(), classList);
printf("Done!\n");
}
@end
+6 -4
View File
@@ -1,7 +1,7 @@
/* NSString+Crypto.h - this file is part of SOGo
*
* Copyright (C) 2012 Nicolas Höft
* Copyright (C) 2012 Inverse inc.
* Copyright (C) 2012-2015 Inverse inc.
*
* Author: Nicolas Höft
* Inverse inc.
@@ -39,13 +39,12 @@ typedef enum {
@interface NSString (SOGoCryptoExtension)
- (BOOL) isEqualToCrypted: (NSString *) cryptedPassword
withDefaultScheme: (NSString *) theScheme;
withDefaultScheme: (NSString *) theScheme;
- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
withSalt: (NSData *) theSalt
andEncoding: (keyEncoding) encoding;
andEncoding: (keyEncoding) encoding;
// this method uses the default encoding (base64, plain, hex)
// and generates a salt when necessary
@@ -56,6 +55,9 @@ typedef enum {
- (NSString *) asSHA1String;
- (NSString *) asMD5String;
- (NSString *) asNTHash;
- (NSString *) asLMHash;
+ (NSArray *) getDefaultEncodingForScheme: (NSString *) passwordScheme;
@end
+42 -8
View File
@@ -1,7 +1,7 @@
/* NSString+Crypto.m - this file is part of SOGo
*
* Copyright (C) 2012 Nicolas Höft
* Copyright (C) 2012 Inverse inc.
* Copyright (C) 2012-2015 Inverse inc.
*
* Author: Nicolas Höft
* Inverse inc.
@@ -29,6 +29,8 @@
#import "NSData+Crypto.h"
#import <NGExtensions/NGBase64Coding.h>
#include "lmhash.h"
@implementation NSString (SOGoCryptoExtension)
/**
@@ -90,7 +92,8 @@
encodingAndScheme = [NSString getDefaultEncodingForScheme: scheme];
pass = [self substringWithRange: range];
// return array with [scheme, password, encoding]
// Returns an array with [scheme, password, encoding]
return [NSArray arrayWithObjects: [encodingAndScheme objectAtIndex: 1], pass, [encodingAndScheme objectAtIndex: 0], nil];
}
@@ -103,7 +106,7 @@
* @return YES if the passwords are identical using this encryption scheme
*/
- (BOOL) isEqualToCrypted: (NSString *) cryptedPassword
withDefaultScheme: (NSString *) theScheme
withDefaultScheme: (NSString *) theScheme
{
NSArray *passInfo;
NSString *selfCrypted;
@@ -193,7 +196,7 @@
*/
- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
withSalt: (NSData *) theSalt
andEncoding: (keyEncoding) userEncoding
andEncoding: (keyEncoding) userEncoding
{
keyEncoding dataEncoding;
NSData* cryptedData;
@@ -229,7 +232,7 @@
{
// base64 encoding
NSString *s = [[NSString alloc] initWithData: [cryptedData dataByEncodingBase64WithLineLength: 1024]
encoding: NSASCIIStringEncoding];
encoding: NSASCIIStringEncoding];
return [s autorelease];
}
@@ -277,7 +280,8 @@
}
// in order to keep backwards-compatibility, hex encoding is used for sha1 here
if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
if ([passwordScheme caseInsensitiveCompare: @"md4"] == NSOrderedSame ||
[passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
[passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame ||
[passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame ||
[passwordScheme caseInsensitiveCompare: @"cram-md5"] == NSOrderedSame)
@@ -294,6 +298,7 @@
{
encoding = encBase64;
}
return [NSArray arrayWithObjects: [NSNumber numberWithInt: encoding], trueScheme, nil];
}
@@ -306,7 +311,7 @@
{
NSData *cryptData;
cryptData = [self dataUsingEncoding: NSUTF8StringEncoding];
return [NSData encodeDataAsHexString: [cryptData asSHA1] ];
return [NSData encodeDataAsHexString: [cryptData asSHA1]];
}
/**
@@ -318,7 +323,36 @@
{
NSData *cryptData;
cryptData = [self dataUsingEncoding: NSUTF8StringEncoding];
return [NSData encodeDataAsHexString: [cryptData asMD5] ];
return [NSData encodeDataAsHexString: [cryptData asMD5]];
}
/**
* Encrypts the data using the NT-hash password scheme.
*
* @return If successful, NT-hash encrypted and with hex encoded string
*/
- (NSString *) asNTHash
{
NSData *d;
d = [self dataUsingEncoding: NSUTF16LittleEndianStringEncoding];
return [[NSData encodeDataAsHexString: [d asMD4]] uppercaseString];
}
/**
* Encrypts the data using the LM-hash password scheme.
*
* @return If successful, LM-hash encrypted and with hex encoded string
*/
- (NSString *) asLMHash
{
NSData *d;
// See http://en.wikipedia.org/wiki/LM_hash#Algorithm
d = [[self uppercaseString] dataUsingEncoding: NSWindowsCP1252StringEncoding];
return [[NSData encodeDataAsHexString: [d asLM]] uppercaseString];
}
@end
+2 -1
View File
@@ -1,6 +1,6 @@
/* SOGoDomainDefaults.h - this file is part of SOGo
*
* Copyright (C) 2009-2014 Inverse inc.
* Copyright (C) 2009-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
@@ -49,6 +49,7 @@
- (BOOL) forceExternalLoginWithEmail;
- (BOOL) sieveScriptsEnabled;
- (BOOL) forwardEnabled;
- (int) forwardConstraints;
- (BOOL) vacationEnabled;
- (NSString *) mailingMechanism;
- (NSString *) smtpServer;
+10 -1
View File
@@ -1,6 +1,6 @@
/* SOGoDomainDefaults.m - this file is part of SOGo
*
* Copyright (C) 2009-2014 Inverse inc.
* Copyright (C) 2009-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
@@ -201,6 +201,15 @@
return [self boolForKey: @"SOGoForwardEnabled"];
}
- (int) forwardConstraints
{
unsigned int v;
v = [self integerForKey: @"SOGoForwardConstraints"];
return (v > 2 ? 0 : v);
}
- (BOOL) vacationEnabled
{
return [self boolForKey: @"SOGoVacationEnabled"];
+1 -1
View File
@@ -1,6 +1,6 @@
/* SOGoFolder.h - this file is part of SOGo
*
* Copyright (C) 2007-2013 Inverse inc.
* 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 -3
View File
@@ -1,8 +1,6 @@
/* SOGoFolder.m - this file is part of SOGo
*
* Copyright (C) 2007-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-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 -1
View File
@@ -1,6 +1,6 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2014 Inverse inc.
Copyright (C) 2006-2015 Inverse inc.
This file is part of SOGo.
+16 -5
View File
@@ -302,7 +302,7 @@ static NSArray *childRecordFields = nil;
}
/* This method fetches the display name defined by the owner, but is also the
fallback when a subscriber has not redefined the display name yet in his
fallback when a subscriber has not redefined the display name yet in their
environment. */
- (NSString *) _displayNameFromOwner
{
@@ -895,7 +895,7 @@ static NSArray *childRecordFields = nil;
allUsers = [NSMutableArray arrayWithArray: [aGroup members]];
// We remove the active user from the group (if present) in order to
// not subscribe him to his own resource!
// not subscribe him to their own resource!
[allUsers removeObject: [context activeUser]];
}
else
@@ -1165,7 +1165,14 @@ static NSArray *childRecordFields = nil;
int syncTokenInt;
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_component",
@"c_creationdate", @"c_lastmodified", nil];
@"c_creationdate", @"c_lastmodified", nil];
if ([[self folderType] isEqualToString: @"Appointment"])
{
[fields addObject: @"c_enddate"];
[fields addObject: @"c_cycleenddate"];
}
addFields = [[properties allValues] objectEnumerator];
while ((currentField = [addFields nextObject]))
if ([currentField length])
@@ -1181,7 +1188,9 @@ static NSArray *childRecordFields = nil;
if (theStartDate)
{
EOQualifier *sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
@"c_creationdate > %d", (int)[theStartDate timeIntervalSince1970]];
@"(c_enddate > %d OR c_enddate = NULL) OR (c_iscycle = 1 and (c_cycleenddate > %d OR c_cycleenddate = NULL))",
(int)[theStartDate timeIntervalSince1970],
(int)[theStartDate timeIntervalSince1970]];
qualifier = [[EOAndQualifier alloc] initWithQualifiers: sinceDateQualifier, qualifier,
nil];
@@ -1211,7 +1220,9 @@ static NSArray *childRecordFields = nil;
if (theStartDate)
{
EOQualifier *sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
@"c_creationdate > %d", (int)[theStartDate timeIntervalSince1970]];
@"(c_enddate > %d OR c_enddate = NULL) OR (c_iscycle = 1 and (c_cycleenddate > %d OR c_cycleenddate = NULL))",
(int)[theStartDate timeIntervalSince1970],
(int)[theStartDate timeIntervalSince1970]];
qualifier = [[EOAndQualifier alloc] initWithQualifiers: sinceDateQualifier, qualifier,
nil];
+1 -3
View File
@@ -1,8 +1,6 @@
/* SOGoMailer.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+2 -4
View File
@@ -1,8 +1,6 @@
/* SOGoMailer.m - this file is part of SOGo
*
* Copyright (C) 2007-2013 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-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
@@ -215,7 +213,7 @@
}
NS_HANDLER
{
NSLog(@"Could not connect to the SMTP server %@ on port %d", host, port);
[self errorWithFormat: @"Could not connect to the SMTP server %@ on port %d", host, port];
result = [NSException exceptionWithHTTPStatus: 500
reason: @"cannot send message:"
@" (smtp) error when connecting"];
+4 -3
View File
@@ -1,14 +1,15 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
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.
+1 -1
View File
@@ -1,7 +1,7 @@
/* SOGoObject.m - this file is part of SOGo
*
* Copyright (C) 2004-2005 SKYRIX Software AG
* Copyright (C) 2006-2013 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
+1 -1
View File
@@ -1,6 +1,6 @@
/* SOGoParentFolder.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
+13 -3
View File
@@ -1,8 +1,6 @@
/* SOGoParentFolder.m - this file is part of SOGo
*
* Copyright (C) 2006-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* 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
@@ -294,6 +292,18 @@ static SoSecurityManager *sm = nil;
subscribedFolder
= [subFolderClass folderWithSubscriptionReference: sourceKey
inContainer: self];
// We check with -ocsFolderForPath if the folder also exists in the database.
// This is important because user A could delete folder X, and user B has subscribed to it.
// If the "default roles" are enabled for calendars/address books, -validatePersmission:.. will
// work (grabbing the default role) and the deleted resource will be incorrectly returned.
//
// FIXME - 2015/01/29 - this fix (24c6c8c91d421594bd51f07904d4cd3911cd187c) was reverted. Normally, we should add
// [subscribedFolder ocsFolderForPath: [subscribedFolder ocsPath]] to check the existence of the folder but it causes
// massive SQL traffic.
//
// The proper fix would be to check upon login and only upon login if GCS folders that we're subscribed to are still existent.
//
if (subscribedFolder
&& ![sm validatePermission: SOGoPerm_AccessObject
onObject: subscribedFolder
+33 -19
View File
@@ -1,6 +1,6 @@
/* SOGoSieveManager.m - this file is part of SOGo
*
* Copyright (C) 2010-2014 Inverse inc.
* Copyright (C) 2010-2015 Inverse inc.
*
* Author: Inverse <info@inverse.ca>
*
@@ -31,6 +31,7 @@
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGStreams/NGInternetSocketAddress.h>
#import <NGImap4/NGSieveClient.h>
@@ -717,7 +718,7 @@ static NSString *sieveScriptName = @"sogo";
client = [[NGSieveClient alloc] initWithURL: url];
if (!client) {
NSLog(@"Sieve connection failed on %@", [url description]);
[self errorWithFormat: @"Sieve connection failed on %@", [url description]];
return nil;
}
@@ -738,19 +739,19 @@ static NSString *sieveScriptName = @"sogo";
if (!connected)
{
NSLog(@"Sieve connection failed on %@", [url description]);
[self errorWithFormat: @"Sieve connection failed on %@", [url description]];
return nil;
}
if (![[result valueForKey:@"result"] boolValue] && !theUsername && !thePassword) {
NSLog(@"failure. Attempting with a renewed password (no authname supported)");
[self logWithFormat: @"failure. Attempting with a renewed password (no authname supported)"];
password = [theAccount imap4PasswordRenewed: YES];
result = [client login: login password: password];
}
if (![[result valueForKey:@"result"] boolValue]) {
NSLog(@"Could not login '%@' on Sieve server: %@: %@",
login, client, result);
[self logWithFormat: @"Could not login '%@' on Sieve server: %@: %@",
login, client, result];
[client closeConnection];
return nil;
}
@@ -823,7 +824,7 @@ static NSString *sieveScriptName = @"sogo";
}
else
{
NSLog(@"Sieve generation failure: %@", [self lastScriptError]);
[self errorWithFormat: @"Sieve generation failure: %@", [self lastScriptError]];
[client closeConnection];
return NO;
}
@@ -834,13 +835,16 @@ static NSString *sieveScriptName = @"sogo";
if (values && [[values objectForKey: @"enabled"] boolValue])
{
NSMutableString *vacation_script;
NSArray *addresses;
NSString *text;
BOOL ignore;
BOOL ignore, alwaysSend;
int days, i;
days = [[values objectForKey: @"daysBetweenResponse"] intValue];
addresses = [values objectForKey: @"autoReplyEmailAddresses"];
alwaysSend = [[values objectForKey: @"alwaysSend"] boolValue];
ignore = [[values objectForKey: @"ignoreLists"] boolValue];
text = [values objectForKey: @"autoReplyText"];
b = YES;
@@ -848,28 +852,38 @@ static NSString *sieveScriptName = @"sogo";
if (days == 0)
days = 7;
vacation_script = [NSMutableString string];
[req addObjectUniquely: @"vacation"];
// Skip mailing lists
if (ignore)
[script appendString: @"if allof ( not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"], not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"], not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\" ) {"];
[vacation_script appendString: @"if allof ( not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"], not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"], not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\" ) {"];
[script appendFormat: @"vacation :days %d :addresses [", days];
[vacation_script appendFormat: @"vacation :days %d :addresses [", days];
for (i = 0; i < [addresses count]; i++)
{
[script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]];
[vacation_script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]];
if (i == [addresses count]-1)
[script appendString: @"] "];
[vacation_script appendString: @"] "];
else
[script appendString: @", "];
[vacation_script appendString: @", "];
}
[script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text];
[vacation_script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text];
if (ignore)
[script appendString: @"}\r\n"];
[vacation_script appendString: @"}\r\n"];
//
// See http://sogo.nu/bugs/view.php?id=2332 for details
//
if (alwaysSend)
[script insertString: vacation_script atIndex: 0];
else
[script appendString: vacation_script];
}
@@ -913,7 +927,7 @@ static NSString *sieveScriptName = @"sogo";
result = [client deleteScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) {
NSLog(@"WARNING: Could not delete Sieve script - continuing...: %@", result);
[self logWithFormat: @"WARNING: Could not delete Sieve script - continuing...: %@", result];
}
// We put and activate the script only if we actually have a script
@@ -923,14 +937,14 @@ static NSString *sieveScriptName = @"sogo";
result = [client putScript: sieveScriptName script: script];
if (![[result valueForKey:@"result"] boolValue]) {
NSLog(@"Could not upload Sieve script: %@", result);
[self logWithFormat: @"Could not upload Sieve script: %@", result];
[client closeConnection];
return NO;
}
result = [client setActiveScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) {
NSLog(@"Could not enable Sieve script: %@", result);
[self logWithFormat: @"Could not enable Sieve script: %@", result];
[client closeConnection];
return NO;
}
+1
View File
@@ -99,6 +99,7 @@
- (int) maximumSyncInterval;
- (int) internalSyncInterval;
- (int) maximumSyncWindowSize;
- (int) maximumSyncResponseSize;
@end
+12
View File
@@ -636,4 +636,16 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
return [self integerForKey: @"SOGoMaximumSyncWindowSize"];
}
- (int) maximumSyncResponseSize
{
int v;
v = [self integerForKey: @"SOGoMaximumSyncResponseSize"];
if (v > 0)
v = v * 1024;
return v;
}
@end
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -31,7 +31,7 @@
Child objects:
'Calendar': SOGoAppointmentFolder
The SOGoUserFolder is the "home directory" of the user where all his
The SOGoUserFolder is the "home directory" of the user where all their
processing starts. It is the 'znek' in such a path:
/SOGo/so/znek/Calendar
*/
+1 -4
View File
@@ -1,9 +1,6 @@
/* SOGoUserManager.h - this file is part of SOGo
*
* Copyright (C) 2007-2013 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@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 -4
View File
@@ -1,9 +1,6 @@
/* SOGoUserManager.m - this file is part of SOGo
*
* Copyright (C) 2007-2013 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@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 -3
View File
@@ -1,8 +1,6 @@
/* SOGoWebDAVAclManager.m - this file is part of SOGo
*
* Copyright (C) 2008 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2008-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 -3
View File
@@ -1,8 +1,6 @@
/* WOContext+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2008 Inverse inc.
*
* Author: Francis Lachapelle <flachapelle@inverse.ca>
* Copyright (C) 2008-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 -3
View File
@@ -1,8 +1,6 @@
/* WOContext+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2008 Inverse inc.
*
* Author: Francis Lachapelle <flachapelle@inverse.ca>
* Copyright (C) 2008-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 -3
View File
@@ -1,8 +1,6 @@
/* WORequest+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2007 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
+5 -1
View File
@@ -1,6 +1,6 @@
/* WORequest+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* 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
@@ -127,10 +127,14 @@
|| [self isAppleDAVWithSubstring: @"iOS/"];
}
//
// Mac+OS+X/10.10.1 (14B25) CalendarAgent/315
//
- (BOOL) isICal
{
return ([self isAppleDAVWithSubstring: @"Mac OS X/10."]
|| [self isAppleDAVWithSubstring: @"Mac_OS_X/"]
|| [self isAppleDAVWithSubstring: @"Mac+OS+X/"]
|| [self isAppleDAVWithSubstring: @"CoreDAV/"]);
}
+742
View File
@@ -0,0 +1,742 @@
#include "lmhash.h"
#include <stddef.h>
#include <stdint.h>
/* ========================================================================== **
*
* LMhash.h
*
* Copyright:
* Copyright (C) 2004 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* $Id: LMhash.h,v 0.1 2004/05/30 02:26:31 crh Exp $
*
* -------------------------------------------------------------------------- **
*
* Description:
*
* Implemention of the LAN Manager hash (LM hash) and LM response
* algorithms.
*
* -------------------------------------------------------------------------- **
*
* License:
*
* This library 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.1 of the License, or (at your option) any later version.
*
* This library 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* -------------------------------------------------------------------------- **
*
* Notes:
*
* This module implements the LM hash. The NT hash is simply the MD4() of
* the password, so we don't need a separate implementation of that. This
* module also implements the LM response, which can be combined with the
* NT hash to produce the NTLM response.
*
* This implementation was created based on the description in my own book.
* The book description was, in turn, written after studying many existing
* examples in various documentation. Jeremy Allison and Andrew Tridgell
* deserve lots of credit for having figured out the secrets of Lan Manager
* authentication many years ago.
*
* See:
* Implementing CIFS - the Common Internet File System
* by your truly. ISBN 0-13-047116-X, Prentice Hall PTR., August 2003
* Section 15.3, in particular.
* (Online at: http://ubiqx.org/cifs/SMB.html#SMB.8.3)
*
* ========================================================================== **
*/
/* Initial permutation map.
* In the first step of DES, the bits of the initial plaintext are rearranged
* according to the map given below. This map and those like it are read by
* the Permute() function (below) which uses the maps as a guide when moving
* bits from one place to another.
*
* Note that the values here are all one less than those shown in Schneier.
* That's because C likes to start counting from 0, not 1.
*
* According to Schneier (Ch12, pg 271), the purpose of the initial
* permutation was to make it easier to load plaintext and ciphertext into
* a DES ecryption chip. I have no idea why that would be the case.
*/
static const uint8_t InitialPermuteMap[64] =
{
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7,
56, 48, 40, 32, 24, 16, 8, 0,
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6
};
/* Key permutation map.
* Like the input data and encryption result, the key is permuted before
* the algorithm really gets going. The original algorithm called for an
* eight-byte key in which each byte contained a parity bit. During the
* key permutiation, the parity bits were discarded. The DES algorithm,
* as used with SMB, does not make use of the parity bits. Instead, SMB
* passes 7-byte keys to DES. For DES implementations that expect parity,
* the parity bits must be added. In this case, however, we're just going
* to start with a 7-byte (56 bit) key. KeyPermuteMap, below, is adjusted
* accordingly and, of course, each entry in the map is reduced by 1 with
* respect to the documented values because C likes to start counting from
* 0, not 1.
*/
static const uint8_t KeyPermuteMap[56] =
{
49, 42, 35, 28, 21, 14, 7, 0,
50, 43, 36, 29, 22, 15, 8, 1,
51, 44, 37, 30, 23, 16, 9, 2,
52, 45, 38, 31, 55, 48, 41, 34,
27, 20, 13, 6, 54, 47, 40, 33,
26, 19, 12, 5, 53, 46, 39, 32,
25, 18, 11, 4, 24, 17, 10, 3,
};
/* Key rotation table.
* At the start of each round of encryption, the key is split and each
* 28-bit half is rotated left. The number of bits of rotation per round
* is given in the table below.
*/
static const uint8_t KeyRotation[16] =
{ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
/* Key compression table.
* This table is used to select 48 of the 56 bits of the key.
* The left and right halves of the source text are each 32 bits,
* but they are expanded to 48 bits and the results are XOR'd
* against the compressed (48-bit) key.
*/
static const uint8_t KeyCompression[48] =
{
13, 16, 10, 23, 0, 4, 2, 27,
14, 5, 20, 9, 22, 18, 11, 3,
25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39,
50, 44, 32, 47, 43, 48, 38, 55,
33, 52, 45, 41, 49, 35, 28, 31
};
/* Data expansion table.
* This table is used after the data block (64-bits) has been split
* into two 32-bit (4-byte) halves (generally denoted L and R).
* Each 32-bit half is "expanded", using this table, to a 48 bit
* data block, which is then XOR'd with the 48 bit subkey for the
* round.
*/
static const uint8_t DataExpansion[48] =
{
31, 0, 1, 2, 3, 4, 3, 4,
5, 6, 7, 8, 7, 8, 9, 10,
11, 12, 11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20, 19, 20,
21, 22, 23, 24, 23, 24, 25, 26,
27, 28, 27, 28, 29, 30, 31, 0
};
/* The (in)famous S-boxes.
* These are used to perform substitutions.
* Six bits worth of input will return four bits of output.
* The four bit values are stored in these tables. Each table has
* 64 entries...and 6 bits provides a number between 0 and 63.
* There are eight S-boxes, one per 6 bits of a 48-bit value.
* Thus, 48 bits are reduced to 32 bits. Obviously, this step
* follows the DataExpansion step.
*
* Note that the literature generally shows this as 8 arrays each
* with four rows and 16 colums. There is a complex formula for
* mapping the 6 bit input values to the correct row and column.
* I've pre-computed that mapping, and the tables below provide
* direct 6-bit input to 4-bit output. See pp 274-274 in Schneier.
*/
static const uint8_t SBox[8][64] =
{
{ /* S0 */
14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13
},
{ /* S1 */
15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9
},
{ /* S2 */
10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12
},
{ /* S3 */
7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14
},
{ /* S4 */
2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3
},
{ /* S5 */
12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13
},
{ /* S6 */
4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12
},
{ /* S7 */
13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
}
};
/* P-Box permutation.
* This permutation is applied to the result of the S-Box Substitutions.
* It's a straight-forward re-arrangement of the bits.
*/
static const uint8_t PBox[32] =
{
15, 6, 19, 20, 28, 11, 27, 16,
0, 14, 22, 25, 4, 17, 30, 9,
1, 7, 23, 13, 31, 26, 2, 8,
18, 12, 29, 5, 21, 10, 3, 24
};
/* Final permutation map.
* This is supposed to be the inverse of the Initial Permutation,
* but there's been a bit of fiddling done.
* As always, the values given are one less than those in the literature
* (because C starts counting from 0, not 1). In addition, the penultimate
* step in DES is to swap the left and right hand sides of the ciphertext.
* The inverse of the Initial Permutation is then applied to produce the
* final result.
* To save a step, the map below does the left/right swap as well as the
* inverse permutation.
*/
static const uint8_t FinalPermuteMap[64] =
{
7, 39, 15, 47, 23, 55, 31, 63,
6, 38, 14, 46, 22, 54, 30, 62,
5, 37, 13, 45, 21, 53, 29, 61,
4, 36, 12, 44, 20, 52, 28, 60,
3, 35, 11, 43, 19, 51, 27, 59,
2, 34, 10, 42, 18, 50, 26, 58,
1, 33, 9, 41, 17, 49, 25, 57,
0, 32, 8, 40, 16, 48, 24, 56
};
/* -------------------------------------------------------------------------- **
* Macros:
*
* CLRBIT( STR, IDX )
* Input: STR - (uchar *) pointer to an array of 8-bit bytes.
* IDX - (int) bitwise index of a bit within the STR array
* that is to be cleared (that is, given a value of 0).
* Notes: This macro clears a bit within an array of bits (which is
* built within an array of bytes).
* - The macro converts to an assignment of the form A &= B.
* - The string of bytes is viewed as an array of bits, read from
* highest order bit first. The highest order bit of a byte
* would, therefore, be bit 0 (within that byte).
*
* SETBIT( STR, IDX )
* Input: STR - (uchar *) pointer to an array of 8-bit bytes.
* IDX - (int) bitwise index of a bit within the STR array
* that is to be set (that is, given a value of 1).
* Notes: This macro sets a bit within an array of bits (which is
* built within an array of bytes).
* - The macro converts to an assignment of the form A |= B.
* - The string of bytes is viewed as an array of bits, read from
* highest order bit first. The highest order bit of a byte
* would, therefore, be bit 0 (within that byte).
*
* GETBIT( STR, IDX )
* Input: STR - (uchar *) pointer to an array of 8-bit bytes.
* IDX - (int) bit-wise index of a bit within the STR array
* that is to be read.
* Output: True (1) if the indexed bit was set, else false (0).
*
* -------------------------------------------------------------------------- **
*/
#define CLRBIT( STR, IDX ) ( (STR)[(IDX)/8] &= ~(0x01 << (7 - ((IDX)%8))) )
#define SETBIT( STR, IDX ) ( (STR)[(IDX)/8] |= (0x01 << (7 - ((IDX)%8))) )
#define GETBIT( STR, IDX ) (( ((STR)[(IDX)/8]) >> (7 - ((IDX)%8)) ) & 0x01)
/* -------------------------------------------------------------------------- **
* Static Functions:
*/
static void Permute( uchar *dst,
const uchar *src,
const uint8_t *map,
const int mapsize )
/* ------------------------------------------------------------------------ **
* Performs a DES permutation, which re-arranges the bits in an array of
* bytes.
*
* Input: dst - Destination into which to put the re-arranged bits.
* src - Source from which to read the bits.
* map - Permutation map.
* mapsize - Number of bytes represented by the <map>. This also
* represents the number of bytes to be copied to <dst>.
*
* Output: none.
*
* Notes: <src> and <dst> must not point to the same location.
*
* - No checks are done to ensure that there is enough room
* in <dst>, or that the bit numbers in <map> do not exceed
* the bits available in <src>. A good reason to make this
* function static (private).
*
* - The <mapsize> value is in bytes. All permutations in DES
* use tables that are a multiple of 8 bits, so there is no
* need to handle partial bytes. (Yes, I know that there
* are some machines out there that still use bytes of a size
* other than 8 bits. For our purposes we'll stick with 8-bit
* bytes.)
*
* ------------------------------------------------------------------------ **
*/
{
int bitcount;
int i;
/* Clear all bits in the destination.
*/
for( i = 0; i < mapsize; i++ )
dst[i] = 0;
/* Set destination bit if the mapped source bit it set. */
bitcount = mapsize * 8;
for( i = 0; i < bitcount; i++ )
{
if( GETBIT( src, map[i] ) )
SETBIT( dst, i );
}
} /* Permute */
static void KeyShift( uchar *key, const int numbits )
/* ------------------------------------------------------------------------ **
* Split the 56-bit key in half & left rotate each half by <numbits> bits.
*
* Input: key - The 56-bit key to be split-rotated.
* numbits - The number of bits by which to rotate the key.
*
* Output: none.
*
* Notes: There are probably several better ways to implement this.
*
* ------------------------------------------------------------------------ **
*/
{
int i;
uchar keep = key[0]; /* Copy the highest order bits of the key. */
/* Repeat the shift process <numbits> times.
*/
for( i = 0; i < numbits; i++ )
{
int j;
/* Shift the entire thing, byte by byte.
*/
for( j = 0; j < 7; j++ )
{
if( j && (key[j] & 0x80) ) /* If the top bit of this byte is set. */
key[j-1] |= 0x01; /* ...shift it to last byte's low bit. */
key[j] <<= 1; /* Then left-shift the whole byte. */
}
/* Now move the high-order bits of each 28-bit half-key to their
* correct locations.
* Bit 27 is the lowest order bit of the first half-key.
* Before the shift, it was the highest order bit of the 2nd half-key.
*/
if( GETBIT( key, 27 ) ) /* If bit 27 is set... */
{
CLRBIT( key, 27 ); /* ...clear bit 27. */
SETBIT( key, 55 ); /* ...set lowest order bit of 2nd half-key. */
}
/* We kept the highest order bit of the first half-key in <keep>.
* If it's set, copy it to bit 27.
*/
if( keep & 0x80 )
SETBIT( key, 27 );
/* Rotate the <keep> byte too, in case <numbits> is 2 and there's
* a second round coming.
*/
keep <<= 1;
}
} /* KeyShift */
static void sbox( uchar *dst, const uchar *src )
/* ------------------------------------------------------------------------ **
* Perform S-Box substitutions.
*
* Input: dst - Destination byte array into which the S-Box substituted
* bitmap will be written.
* src - Source byte array.
*
* Output: none.
*
* Notes: It's really not possible (for me, anyway) to understand how
* this works without reading one or more detailed explanations.
* Quick overview, though:
*
* After the DataExpansion step (in which a 32-bit bit array is
* expanded to a 48-bit bit array) the expanded data block is
* XOR'd with 48-bits worth of key. That 48 bits then needs to
* be condensed back into 32 bits.
*
* The S-Box substitution handles the data reduction by breaking
* the 48-bit value into eight 6-bit values. For each of these
* 6-bit values there is a table (an S-Box table). The table
* contains 64 possible values. Conveniently, a 6-bit integer
* can represent a value between 0 and 63.
*
* So, if you think of the 48-bit bit array as an array of 6-bit
* integers, you use S-Box table 0 with the 0th 6-bit value.
* Table 1 is used with the 6-bit value #1, and so on until #7.
* Within each table, the correct substitution is found based
* simply on the value of the 6-bit integer.
*
* Well, the original algorithm (and most documentation) don't
* make it so simple. There's a complex formula for mapping
* the 6-bit values to the correct substitution. Fortunately,
* those lookups can be precomputed (and have been for this
* implementation). See pp 274-274 in Schneier.
*
* Oh, and the substitute values are all 4-bit values, so each
* 6-bits gets reduced to 4-bits resulting in a 32-bit bit array.
*
* ------------------------------------------------------------------------ **
*/
{
int i;
/* Clear the destination array.
*/
for( i = 0; i < 4; i++ )
dst[i] = 0;
/* For each set of six input bits...
*/
for( i = 0; i < 8; i++ )
{
int j;
int Snum;
int bitnum;
/* Extract the 6-bit integer from the source.
* This will be the lookup key within the SBox[i] array.
*/
for( Snum = j = 0, bitnum = (i * 6); j < 6; j++, bitnum++ )
{
Snum <<= 1;
Snum |= GETBIT( src, bitnum );
}
/* Find the correct value in the correct SBox[]
* and copy it into the destination.
* Left shift the nibble four bytes for even values of <i>.
*/
if( 0 == (i%2) )
dst[i/2] |= ((SBox[i][Snum]) << 4);
else
dst[i/2] |= SBox[i][Snum];
}
} /* sbox */
static void xor( uchar *dst, const uchar *a, const uchar *b, const int count )
/* ------------------------------------------------------------------------ **
* Perform an XOR operation on two byte arrays.
*
* Input: dst - Destination array to which the result will be written.
* a - The first string of bytes.
* b - The second string of bytes.
* count - Number of bytes to XOR against one another.
*
* Output: none.
*
* Notes: This function operates on whole byte chunks. There's no need
* to XOR partial bytes so no need to write code to handle it.
*
* - This function essentially implements dst = a ^ b; for byte
* arrays.
*
* - <dst> may safely point to the same location as <a> or <b>.
*
* ------------------------------------------------------------------------ **
*/
{
int i;
for( i = 0; i < count; i++ )
dst[i] = a[i] ^ b[i];
} /* xor */
/* -------------------------------------------------------------------------- **
* Functions:
*/
uchar *auth_DESkey8to7( uchar *dst, const uchar *key )
/* ------------------------------------------------------------------------ **
* Compress an 8-byte DES key to its 7-byte form.
*
* Input: dst - Pointer to a memory location (minimum 7 bytes) to accept
* the compressed key.
* key - Pointer to an 8-byte DES key. See the notes below.
*
* Output: A pointer to the compressed key (same as <dst>) or NULL if
* either <src> or <dst> were NULL.
*
* Notes: There are no checks done to ensure that <dst> and <key> point
* to sufficient space. Please be carefull.
*
* The two pointers, <dst> and <key> may point to the same
* memory location. Internally, a temporary buffer is used and
* the results are copied back to <dst>.
*
* The DES algorithm uses 8 byte keys by definition. The first
* step in the algorithm, however, involves removing every eigth
* bit to produce a 56-bit key (seven bytes). SMB authentication
* skips this step and uses 7-byte keys. The <auth_DEShash()>
* algorithm in this module expects 7-byte keys. This function
* is used to convert an 8-byte DES key into a 7-byte SMB DES key.
*
* ------------------------------------------------------------------------ **
*/
{
int i;
uchar tmp[7];
static const uint8_t map8to7[56] =
{
0, 1, 2, 3, 4, 5, 6,
8, 9, 10, 11, 12, 13, 14,
16, 17, 18, 19, 20, 21, 22,
24, 25, 26, 27, 28, 29, 30,
32, 33, 34, 35, 36, 37, 38,
40, 41, 42, 43, 44, 45, 46,
48, 49, 50, 51, 52, 53, 54,
56, 57, 58, 59, 60, 61, 62
};
if( (NULL == dst) || (NULL == key) )
return( NULL );
Permute( tmp, key, map8to7, 7 );
for( i = 0; i < 7; i++ )
dst[i] = tmp[i];
return( dst );
} /* auth_DESkey8to7 */
uchar *auth_DEShash( uchar *dst, const uchar *key, const uchar *src )
/* ------------------------------------------------------------------------ **
* DES encryption of the input data using the input key.
*
* Input: dst - Destination buffer. It *must* be at least eight bytes
* in length, to receive the encrypted result.
* key - Encryption key. Exactly seven bytes will be used.
* If your key is shorter, ensure that you pad it to seven
* bytes.
* src - Source data to be encrypted. Exactly eight bytes will
* be used. If your source data is shorter, ensure that
* you pad it to eight bytes.
*
* Output: A pointer to the encrpyted data (same as <dst>).
*
* Notes: In SMB, the DES function is used as a hashing function rather
* than an encryption/decryption tool. When used for generating
* the LM hash the <src> input is the known value "KGS!@#$%" and
* the key is derived from the password entered by the user.
* When used to generate the LM or NTLM response, the <key> is
* derived from the LM or NTLM hash, and the challenge is used
* as the <src> input.
* See: http://ubiqx.org/cifs/SMB.html#SMB.8.3
*
* - This function is called "DEShash" rather than just "DES"
* because it is only used for creating LM hashes and the
* LM/NTLM responses. For all practical purposes, however, it
* is a full DES encryption implementation.
*
* - This DES implementation does not need to be fast, nor is a
* DES decryption function needed. The goal is to keep the
* code small, simple, and well documented.
*
* - The input values are copied and refiddled within the module
* and the result is not written to <dst> until the very last
* step, so it's okay if <dst> points to the same memory as
* <key> or <src>.
*
* ------------------------------------------------------------------------ **
*/
{
int i; /* Loop counter. */
uchar K[7]; /* Holds the key, as we manipulate it. */
uchar D[8]; /* The data block, as we manipulate it. */
/* Create the permutations of the key and the source.
*/
Permute( K, key, KeyPermuteMap, 7 );
Permute( D, src, InitialPermuteMap, 8 );
/* DES encryption proceeds in 16 rounds.
* The stuff inside the loop is known in the literature as "function f".
*/
for( i = 0; i < 16; i++ )
{
int j;
uchar *L = D; /* The left 4 bytes (half) of the data block. */
uchar *R = &(D[4]); /* The right half of the ciphertext block. */
uchar Rexp[6]; /* Expanded right half. */
uchar Rn[4]; /* New value of R, as we manipulate it. */
uchar SubK[6]; /* The 48-bit subkey. */
/* Generate the subkey for this round.
*/
KeyShift( K, KeyRotation[i] );
Permute( SubK, K, KeyCompression, 6 );
/* Expand the right half (R) of the data block to 48 bytes,
* then XOR the result with the Subkey for this round.
*/
Permute( Rexp, R, DataExpansion, 6 );
xor( Rexp, Rexp, SubK, 6 );
/* S-Box substitutions, P-Box permutation, and final XOR.
* The S-Box substitutions return a 32-bit value, which is then
* run through the 32-bit to 32-bit P-Box permutation. The P-Box
* result is then XOR'd with the left-hand half of the key.
* (Rexp is used as a temporary variable between the P-Box & XOR).
*/
sbox( Rn, Rexp );
Permute( Rexp, Rn, PBox, 4 );
xor( Rn, L, Rexp, 4 );
/* The previous R becomes the new L,
* and Rn is moved into R ready for the next round.
*/
for( j = 0; j < 4; j++ )
{
L[j] = R[j];
R[j] = Rn[j];
}
}
/* The encryption is complete.
* Now reverse-permute the ciphertext to produce the final result.
* We actually combine two steps here. The penultimate step is to
* swap the positions of L and R in the result of the 16 rounds,
* after which the reverse of the Initial Permutation is applied.
* To save a step, the FinalPermuteMap applies both the L/R swap
* and the inverse of the Initial Permutation.
*/
Permute( dst, D, FinalPermuteMap, 8 );
return( dst );
} /* auth_DEShash */
static const uchar SMB_LMhash_Magic[8] =
{ 'K', 'G', 'S', '!', '@', '#', '$', '%' };
uchar *auth_LMhash( uchar *dst, const uchar *pwd, const int pwdlen )
/* ------------------------------------------------------------------------ **
* Generate an LM Hash from the input password.
*
* Input: dst - Pointer to a location to which to write the LM Hash.
* Requires 16 bytes minimum.
* pwd - Source password. Should be in OEM charset (extended
* ASCII) format in all upper-case, but this
* implementation doesn't really care. See the notes
* below.
* pwdlen - Length, in bytes, of the password. Normally, this
* will be strlen( pwd ).
*
* Output: Pointer to the resulting LM hash (same as <dst>).
*
* Notes: This function does not convert the input password to upper
* case. The upper-case conversion should be done before the
* password gets this far. DOS codepage handling and such
* should be taken into consideration. Rather than attempt to
* work out all those details here, the function assumes that
* the password is in the correct form before it reaches this
* point.
*
* ------------------------------------------------------------------------ **
*/
{
int i,
max14;
uint8_t tmp_pwd[14] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
/* Copy at most 14 bytes of <pwd> into <tmp_pwd>.
* If the password is less than 14 bytes long
* the rest will be nul padded.
*/
max14 = pwdlen > 14 ? 14 : pwdlen;
for( i = 0; i < max14; i++ )
tmp_pwd[i] = pwd[i];
/* The password is split into two 7-byte keys, each of which
* are used to DES-encrypt the magic string. The results are
* concatonated to produce the 16-byte LM Hash.
*/
(void)auth_DEShash( dst, tmp_pwd, SMB_LMhash_Magic );
(void)auth_DEShash( &dst[8], &tmp_pwd[7], SMB_LMhash_Magic );
/* Return a pointer to the result.
*/
return( dst );
} /* auth_LMhash */
+95
View File
@@ -0,0 +1,95 @@
#ifndef AUTH_LMHASH_H
#define AUTH_LMHASH_H
typedef unsigned char uchar;
/* ========================================================================== **
*
* LMhash.h
*
* Copyright:
* Copyright (C) 2004 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* $Id: LMhash.h,v 0.1 2004/05/30 02:26:31 crh Exp $
*
* -------------------------------------------------------------------------- **
*
* Description:
*
* Implemention of the LAN Manager hash (LM hash) and LM response
* algorithms.
*
* -------------------------------------------------------------------------- **
*
* License:
*
* This library 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.1 of the License, or (at your option) any later version.
*
* This library 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* -------------------------------------------------------------------------- **
*
* Notes:
*
* This module implements the LM hash. The NT hash is simply the MD4() of
* the password, so we don't need a separate implementation of that. This
* module also implements the LM response, which can be combined with the
* NT hash to produce the NTLM response.
*
* This implementation was created based on the description in my own book.
* The book description was, in turn, written after studying many existing
* examples in various documentation. Jeremy Allison and Andrew Tridgell
* deserve lots of credit for having figured out the secrets of Lan Manager
* authentication many years ago.
*
* See:
* Implementing CIFS - the Common Internet File System
* by your truly. ISBN 0-13-047116-X, Prentice Hall PTR., August 2003
* Section 15.3, in particular.
* (Online at: http://ubiqx.org/cifs/SMB.html#SMB.8.3)
*
* ========================================================================== **
*/
/* -------------------------------------------------------------------------- **
* Functions:
*/
uchar *auth_LMhash( uchar *dst, const uchar *pwd, const int pwdlen );
/* ------------------------------------------------------------------------ **
* Generate an LM Hash from the input password.
*
* Input: dst - Pointer to a location to which to write the LM Hash.
* Requires 16 bytes minimum.
* pwd - Source password. Should be in OEM charset (extended
* ASCII) format in all upper-case, but this
* implementation doesn't really care. See the notes
* below.
* pwdlen - Length, in bytes, of the password. Normally, this
* will be strlen( pwd ).
*
* Output: Pointer to the resulting LM hash (same as <dst>).
*
* Notes: This function does not convert the input password to upper
* case. The upper-case conversion should be done before the
* password gets this far. DOS codepage handling and such
* should be taken into consideration. Rather than attempt to
* work out all those details here, the function assumes that
* the password is in the correct form before it reaches this
* point.
*
* ------------------------------------------------------------------------ **
*/
#endif
+1 -3
View File
@@ -1,8 +1,6 @@
/* SOGoTool.h - this file is part of SOGo
*
* Copyright (C) 2009-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2009-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 -3
View File
@@ -1,8 +1,6 @@
/* SOGoTool.m - this file is part of SOGo
*
* Copyright (C) 2009-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2009-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 -1
View File
@@ -254,7 +254,7 @@ typedef enum
//
// to achieve what we want.
//
if (o && [o count] == 1)
if (o && [o isKindOfClass: [NSDictionary class]] && [o count] == 1)
{
[source setObject: [[o allValues] lastObject] forKey: key];
}
+1 -1
View File
@@ -106,7 +106,7 @@
acquire: NO];
if ([test isKindOfClass: [NSException class]])
{
NSLog (@"%@ not found", [card reference]);
//NSLog (@"%@ not found", [card reference]);
cardCopy = [card copy];
[invalid addObject: cardCopy];
[cardCopy release];
+5 -1
View File
@@ -272,7 +272,7 @@ static NSData* _sanitizeContent(NSData *theData)
if ([tag caseInsensitiveCompare: found_tag] == NSOrderedSame)
{
// Remove the leading slash
NSLog(@"Found void tag with invalid leading slash: </%@>", found_tag);
//NSLog(@"Found void tag with invalid leading slash: </%@>", found_tag);
i--;
[d replaceBytesInRange: NSMakeRange(i, 1)
withBytes: NULL
@@ -455,6 +455,10 @@ static NSData* _sanitizeContent(NSData *theData)
{
if (*currentChar == '{')
inCSSDeclaration = YES;
if (*currentChar == '}')
// CSS syntax error: ending declaration character while not in a CSS declaration.
// Ignore eveything from last CSS declaration.
start = currentChar + 1;
else if (*currentChar == ',')
hasEmbeddedCSS = NO;
else if (!hasEmbeddedCSS)
+1 -1
View File
@@ -436,7 +436,7 @@ static NSArray *infoKeys = nil;
- (NSDictionary *) storeInfo
{
[self debugWithFormat:@"storing info ..."];
return [self valuesForKeys: infoKeys];
return [self dictionaryWithValuesForKeys: infoKeys];
}
/* contacts search */
+9 -2
View File
@@ -712,19 +712,26 @@
WORequest *request;
SOGoMailFolder *co;
NSException *error;
NSArray *msgUIDs, *flags;
NSArray *msgUIDs;
NSMutableArray *flags;
NSString *operation;
NSDictionary *content, *result;
BOOL addOrRemove;
NGImap4Client *client;
int i;
request = [context request];
content = [[request contentAsString] objectFromJSONString];
flags = [NSArray arrayWithObject:[content objectForKey:@"flags"]];
flags = [NSMutableArray arrayWithObject:[content objectForKey:@"flags"]];
msgUIDs = [NSArray arrayWithArray:[content objectForKey:@"msgUIDs"]];
operation = [content objectForKey:@"operation"];
addOrRemove = ([operation isEqualToString:@"add"]? YES: NO);
// We unescape our flags
for (i = [flags count]-1; i >= 0; i--)
[flags replaceObjectAtIndex: i withObject: [[flags objectAtIndex: i] fromCSSIdentifier]];
co = [self clientObject];
client = [[co imap4Connection] client];
[[co imap4Connection] selectFolder: [co imap4URL]];
+1 -1
View File
@@ -77,7 +77,7 @@ static NSString *mailETag = nil;
SOGO_MAJOR_VERSION,
SOGO_MINOR_VERSION,
SOGO_SUBMINOR_VERSION];
NSLog (@"Note: using constant etag for mail viewer: '%@'", mailETag);
//NSLog (@"Note: using constant etag for mail viewer: '%@'", mailETag);
}
- (void) dealloc
+7 -1
View File
@@ -21,6 +21,8 @@
#import <Foundation/NSBundle.h>
#import <SOGo/SOGoCache.h>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/SOGoFolder.h>
#import <NGObjWeb/NSException+HTTP.h>
@@ -54,13 +56,17 @@
ex = [dispatcher dispatchRequest: request inResponse: response context: context];
//[[self class] memoryStatistics];
if (ex)
{
return [NSException exceptionWithHTTPStatus: 500];
}
RELEASE(dispatcher);
[[SOGoCache sharedCache] killCache];
return response;
}
+1 -1
View File
@@ -361,7 +361,7 @@
if (login)
{
/* We redirect the user to his "homepage" when newLocation could not be
/* We redirect the user to their "homepage" when newLocation could not be
deduced from the "cas-location" cookie and the current action is not a
login callback (ticket != nil). */
if (!newLocation || !ticket)
+8 -5
View File
@@ -1,6 +1,6 @@
/* SOGoUserHomePage.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* 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
@@ -103,8 +103,8 @@
maxBookings = [user numberOfSimultaneousBookings];
isResource = [user isResource];
// Don't fetch freebusy information if the user is of type 'resource' and has unlimited bookings
if (!isResource || maxBookings > 0)
// Fetch freebusy information if the user is NOT a resource or if multiplebookings isn't unlimited
if (!isResource || maxBookings != 0)
{
for (recordCount = 0; recordCount < recordMax; recordCount++)
{
@@ -167,10 +167,10 @@
endInterval += (delta/60/15);
// Update bit string representation
// If the user is a resource, keep the sum of overlapping events
// If the user is a resource with restristed amount of bookings, keep the sum of overlapping events
for (count = startInterval; count < endInterval; count++)
{
*(items + count) = isResource ? *(items + count) + 1 : 1;
*(items + count) = (isResource && maxBookings > 0) ? *(items + count) + 1 : 1;
}
}
}
@@ -189,6 +189,9 @@
}
}
//
//
//
- (NSString *) _freeBusyFromStartDate: (NSCalendarDate *) startDate
toEndDate: (NSCalendarDate *) endDate
forFreeBusy: (SOGoFreeBusyObject *) fb
@@ -153,6 +153,9 @@
"displayremoteinlineimages_never" = "Nunca";
"displayremoteinlineimages_always" = "Sempre";
"Auto save every" = "Auto salvar cada";
"minutes" = "minutos";
/* Contact */
"Personal Address Book" = "Catálogo Pessoal";
"Collected Address Book" = "Catálogo Coletado";
@@ -29,6 +29,7 @@
"Days between responses :" = "Počet dnů mezi odpověďmi :";
"Do not send responses to mailing lists" = "Neposílat odpovědi do konferencí";
"Disable auto reply on" = "Automatické odpovědi vypnout dne";
"Always send vacation message response" = "Vždy posílat zprávu v nepřítomnosti";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Prosím zadejte text zprávy a své emailové adresy, pro které chcete zasílání v nepřítomnosti použít.";
"Your vacation message must not end with a single dot on a line." = "Vaše zpráva v nepřítomnosti nesmí končit samotnou tečkou na řádce.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Ponechat kopii";
"Please specify an address to which you want to forward your messages."
= "Prosím zadejte adresu, na kterou chcete své zprávy přeposílat.";
"You are not allowed to forward your messages to an external email address." = "Nemáte povoleno přeposílání Vašich zpráv na externí emailovou adresu.";
"You are not allowed to forward your messages to an internal email address." = "Nemáte povoleno přeposílání Vašich zpráv na interní emailovou adresu.";
/* d & t */
"Current Time Zone :" = "Současné časové pásmo :";
@@ -29,6 +29,7 @@
"Days between responses :" = "Days between responses:";
"Do not send responses to mailing lists" = "Do not send responses to mailing lists";
"Disable auto reply on" = "Disable auto reply on";
"Always send vacation message response" = "Always send vacation message response";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Please specify your message and your email addresses for which you want to enable auto reply.";
"Your vacation message must not end with a single dot on a line." = "Your vacation message must not end with a single dot on a line.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Keep a copy";
"Please specify an address to which you want to forward your messages."
= "Please specify an address to which you want to forward your messages.";
"You are not allowed to forward your messages to an external email address." = "You are not allowed to forward your messages to an external email address.";
"You are not allowed to forward your messages to an internal email address." = "You are not allowed to forward your messages to an internal email address.";
/* d & t */
"Current Time Zone :" = "Current Time Zone:";
@@ -29,6 +29,7 @@
"Days between responses :" = "Päivät vastausten välillä:";
"Do not send responses to mailing lists" = "Älä lähetä vastauksia postituslistoille";
"Disable auto reply on" = "Poista automaattivastaus käytöstä";
"Always send vacation message response" = "Lähetä lomaviestivastaus aina";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Ole hyvä ja määritä viesti sekä sähköpostiosoitteet joille haluat aktivoida automaattivastauksen.";
"Your vacation message must not end with a single dot on a line." = "Lomaviestisi ei saa päättyä yksittäiseen pisteeseen viimeisellä rivillä.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Pidä kopio";
"Please specify an address to which you want to forward your messages."
= "Ole hyvä ja määritä sähköpostiosoite johon haluat edelleenlähettää viestisi.";
"You are not allowed to forward your messages to an external email address." = "Sinulla ei ole lupaa välittää viestejä ulkoiseen sähköpostiosoitteeseen.";
"You are not allowed to forward your messages to an internal email address." = "Sinulla ei ole lupaa välittää viestejä sisäiseen sähköpostiosoitteeseen.";
/* d & t */
"Current Time Zone :" = "Nykyinen aikavyöhyke:";
@@ -29,6 +29,7 @@
"Days between responses :" = "Nombre de jours entre réponses :";
"Do not send responses to mailing lists" = "Ne pas envoyer les réponses aux listes de diffusion";
"Disable auto reply on" = "Désactiver la réponse automatique le";
"Always send vacation message response" = "Toujours envoyer le message de vacances prolongées";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Veuillez définir un message et vos adresses pour lesquelles pour désirez activer une réponse automatique.";
"Your vacation message must not end with a single dot on a line." = "Le message de vacances ne doit pas se terminer par une ligne ne contenant qu'un point.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Garder une copie";
"Please specify an address to which you want to forward your messages."
= "Veuillez définir une adresse à laquelle vous désirez transférer automatiquement vos nouveaux messages.";
"You are not allowed to forward your messages to an external email address." = "Il est interdit de renvoyer vos messages vers une adresse externe.";
"You are not allowed to forward your messages to an internal email address." = "Il est interdit de renvoyer vos messages vers une adresse interne.";
/* d & t */
"Current Time Zone :" = "Fuseau horaire en cours :";
@@ -29,6 +29,7 @@
"Days between responses :" = "Tage zwischen automatischen Abwesenheitsnachrichten:";
"Do not send responses to mailing lists" = "Keine automatischen Abwesenheitsnachrichten an Mailinglisten senden";
"Disable auto reply on" = "Automatische Abwesenheitsnachricht abschalten am";
"Always send vacation message response" = "Immer Abwesenheitsmeldung senden";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Bitte ihren Nachrichtentext und ihre E-Mail-Adressen angeben, für die automatische Abwesenheitsnachrichten aktiviert werden sollen.";
"Your vacation message must not end with a single dot on a line." = "Ihre Abwesenheitsnachricht darf nicht mit einem alleinstehenden Punkt in einer Zeile enden.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Eine Kopie behalten";
"Please specify an address to which you want to forward your messages."
= "Bitte Adresse angeben, an die Ihre Nachrichten weitergeleitet werden sollen.";
"You are not allowed to forward your messages to an external email address." = "Es ist Ihnen nicht erlaubt, Ihre Nachrichten an externe E-Mail-Adressen weiterzuleiten.";
"You are not allowed to forward your messages to an internal email address." = "Es ist Ihnen nicht erlaubt, Ihre Nachrichten an interne E-Mail-Adressen weiterzuleiten.";
/* d & t */
"Current Time Zone :" = "Aktuelle Zeitzone:";
@@ -29,6 +29,7 @@
"Days between responses :" = "Válaszok közötti napok száma:";
"Do not send responses to mailing lists" = "Levelező listákra válasz mellőzése";
"Disable auto reply on" = "Automatikus válasz tiltása";
"Always send vacation message response" = "Mindig küldjön távollét üzenet választ";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Kérem adja meg az üzenetét valamint a címeket, amelyekre engedélyezi az automatikus válasz küldését.";
"Your vacation message must not end with a single dot on a line." = "A távollét üzenet utolsó sora nem tartalmazhat egy egyedülálló . karatert.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Másolat megtartása";
"Please specify an address to which you want to forward your messages."
= "Kérem adjon meg egy címet, amelyre a leveleit továbbítani kívánja.";
"You are not allowed to forward your messages to an external email address." = "Ön számára nem endélyezett az üzenetek továbbítása külső email címre.";
"You are not allowed to forward your messages to an internal email address." = "Ön számára nem endélyezett az üzenetek továbbítása belső email címre.";
/* d & t */
"Current Time Zone :" = "Időzóna :";
@@ -153,6 +157,9 @@
"displayremoteinlineimages_never" = "Soha";
"displayremoteinlineimages_always" = "Mindig";
"Auto save every" = "Automatikus mentés gyakorisága";
"minutes" = "perc";
/* Contact */
"Personal Address Book" = "Személyes címjegyzék";
"Collected Address Book" = "Összegyűjtöt címek jegyzéke";
+34 -1
View File
@@ -1,6 +1,6 @@
/* UIxPreferences.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* 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
@@ -1127,6 +1127,30 @@ static NSArray *reminderValues = nil;
return ignore;
}
//
// See http://sogo.nu/bugs/view.php?id=2332 for details
//
- (void) setAlwaysSend: (BOOL) ignoreLists
{
[vacationOptions setObject: [NSNumber numberWithBool: ignoreLists]
forKey: @"alwaysSend"];
}
- (BOOL) alwaysSend
{
NSNumber *obj;
BOOL ignore;
obj = [vacationOptions objectForKey: @"alwaysSend"];
if (obj == nil)
ignore = NO; // defaults to NO
else
ignore = [obj boolValue];
return ignore;
}
- (BOOL) enableVacationEndDate
{
return [[vacationOptions objectForKey: @"endDateEnabled"] boolValue];
@@ -1214,6 +1238,15 @@ static NSArray *reminderValues = nil;
return [[forwardOptions objectForKey: @"keepCopy"] boolValue];
}
- (NSString *) forwardConstraints
{
SOGoDomainDefaults *dd;
dd = [[context activeUser] domainDefaults];
return [NSString stringWithFormat: @"%d", [dd forwardConstraints]];
}
/* main */
- (NSArray *) availableModules
+2 -4
View File
@@ -1,8 +1,6 @@
/* UIxCalView.m - this file is part of SOGo
*
* Copyright (C) 2006-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* 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
@@ -584,7 +582,7 @@
[uri appendString: @"Groups/_custom_"];
[uri appendString: uidsString];
[uri appendString: @"/"];
NSLog (@"Group URI = '%@'", uri);
//NSLog (@"Group URI = '%@'", uri);
}
else
{
+7 -4
View File
@@ -1,6 +1,6 @@
/* UIxComponentEditor.m - 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
@@ -594,7 +594,7 @@ iRANGE(2);
ASSIGN (reminderUnit, @"MINUTES");
break;
default:
NSLog(@"Cannot process duration unit: '%c'", c);
//NSLog(@"Cannot process duration unit: '%c'", c);
break;
}
}
@@ -1428,7 +1428,8 @@ iRANGE(2);
- (void) setComponentCalendar: (SOGoAppointmentFolder *) _componentCalendar
{
ASSIGN(componentCalendar, _componentCalendar);
if (_componentCalendar)
ASSIGN(componentCalendar, _componentCalendar);
}
/* priorities */
@@ -1886,7 +1887,9 @@ RANGE(2);
[component setAttendees: newAttendees];
}
else
NSLog(@"Error scanning following JSON:\n%@", json);
{
//NSLog(@"Error scanning following JSON:\n%@", json);
}
}
}
+13 -4
View File
@@ -600,7 +600,7 @@
<var:string label:value="Add default email addresses" /></span></a>
</span>
</label><br/>
<label><var:string label:value="Days between responses :"/>
<var:popup list="daysBetweenResponsesList" item="item"
const:id="daysBetweenResponsesList"
@@ -623,8 +623,14 @@
date="vacationEndDate"
const:dayStartHour="0"
const:dayEndHour="23"
/>
/><br/>
<label><input type="checkbox"
const:name="alwaysSend"
const:id="alwaysSend"
var:checked="alwaysSend" />
<var:string label:value="Always send vacation message response" /></label><br/>
</div>
</div>
</var:if
@@ -647,7 +653,10 @@
const:name="forwardKeepCopy"
const:id="forwardKeepCopy"
var:checked="forwardKeepCopy" />
<var:string label:value="Keep a copy" /></label><br/>
<var:string label:value="Keep a copy" /></label><br/>
<script type="text/javascript">
var forwardConstraints = <var:string value="forwardConstraints" const:escapeHTML="NO"/>;
</script>
</div>
</div>
</var:if>
@@ -12,7 +12,7 @@
</var:if>
<var:if condition="isBody">
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<!--
You can subscribe directly to that folder by following this link:
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>subscribe?mail-invitation=YES
@@ -12,7 +12,7 @@
</var:if>
<var:if condition="isBody">
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<!--
You can unsubscribe directly to that folder by following this link:
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>unsubscribe?mail-invitation=YES
@@ -12,7 +12,7 @@
</var:if>
<var:if condition="isBody">
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<var:string value="currentUserName" const:escapeHTML="NO"/> has modified your access rights for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<!--
You can subscribe directly to that folder by following this link:
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>subscribe?mail-invitation=YES
+1 -1
View File
@@ -12,7 +12,7 @@
</var:if>
<var:if condition="isBody">
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for his <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<var:string value="currentUserName" const:escapeHTML="NO"/> has removed you from the access list for their <var:string const:value='"' const:escapeHTML="NO"/><var:string value="resourceName" const:escapeHTML="NO"/><var:string const:value='"' const:escapeHTML="NO"/> folder.
<!--
You can unsubscribe directly to that folder by following this link:
<var:string value="httpAdvisoryURL" const:escapeHTML="NO"/>unsubscribe?mail-invitation=YES
Loaded 100 of 105 files, more files were not shown because too many files have changed in this diff. Show more