merging conflicts

pull/44/head
Alexandre Cloutier 2014-06-30 10:55:55 -04:00
commit d197ab71b7
27 changed files with 658 additions and 298 deletions

View File

@ -126,6 +126,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncKey"];
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] addEntriesFromDictionary: theFolderMetadata];
[o save];
@ -477,21 +478,70 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
lastServerKey: (NSString **) theLastServerKey
{
NSMutableDictionary *folderMetadata;
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
NSMutableString *s;
BOOL more_available;
int i, max;
s = [NSMutableString string];
more_available = NO;
if (theFolderType == ActiveSyncMailFolder && !([theSyncKey isEqualToString: @"-1"]) && theFilterType)
{
NSArray *allKeys;
NSString *key;
int softdelete_count;
softdelete_count = 0;
folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
dateCache = [folderMetadata objectForKey: @"DateCache"];
syncCache = [folderMetadata objectForKey: @"SyncCache"];
allKeys = [dateCache allKeys];
for (i = 0; i < [allKeys count]; i++)
{
key = [allKeys objectAtIndex: i];
if ([[dateCache objectForKey:key] compare: theFilterType] == NSOrderedAscending)
{
[s appendString: @"<SoftDelete xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", key];
[s appendString: @"</SoftDelete>"];
[syncCache removeObjectForKey: key];
[dateCache removeObjectForKey: key];
softdelete_count++;
}
if (softdelete_count >= theWindowSize)
{
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
[self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
more_available = YES;
*theLastServerKey = theSyncKey;
// Since WindowSize is reached don't even try to add more to the response, let's just
// jump to the end and return the response immediately
goto return_response;
}
}
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
}
//
// No changes in the collection - 2.2.2.19.1.1 Empty Sync Request.
// We check this and we don't generate any commands if we don't have to.
//
if ([theSyncKey isEqualToString: [theCollection davCollectionTag]])
if ([theSyncKey isEqualToString: [theCollection davCollectionTag]] && !([s length]))
return;
s = [NSMutableString string];
more_available = NO;
switch (theFolderType)
@ -614,7 +664,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
case ActiveSyncMailFolder:
default:
{
NSMutableDictionary *syncCache, *dateCache;
SOGoSyncCacheObject *lastCacheObject, *aCacheObject;
NSMutableArray *allCacheObjects, *sortedBySequence;
@ -644,6 +693,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"SyncCache"];
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"DateCache"];
}
// Check whether GUID in cache is equal to the GUID from imap - this is to avoid cache corruptions if a folder has been renamed and a new folder
// with the same name has been created but folderSync has not yet updated the cache
if (!([[theCollection nameInContainer] isEqualToString:
@ -805,6 +855,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
break;
} // switch (folderType) ...
return_response:
if ([s length])
{
[theBuffer appendString: @"<Commands>"];
@ -1008,7 +1060,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
davCollectionTag = [collection davCollectionTag];
}
// Generate the response buffer
[theBuffer appendString: @"<Collection>"];

View File

@ -64,6 +64,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeFileData.h>
#import <NGMime/NGMimeMultipartBody.h>
#import <NGMime/NGMimeType.h>
#import <NGMail/NGMimeMessageParser.h>
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
@ -170,6 +171,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return [o properties];
}
- (unsigned int) _softDeleteCountWithFilter: (NSCalendarDate *) theFilter
collectionId: (NSString *) theCollectionId
{
NSMutableDictionary *dateCache;
NSMutableArray *sdUids;
SOGoCacheGCSObject *o;
NSArray *allKeys;
NSString *key;
int i;
sdUids = [NSMutableArray array];
if (theFilter)
{
o = [SOGoCacheGCSObject objectWithName: [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], theCollectionId] inContainer: nil];
[o setObjectType: ActiveSyncGlobalCacheObject];
[o setTableUrl: [self folderTableURL]];
[o reloadIfNeeded];
dateCache = [[o properties] objectForKey: @"DateCache"];
allKeys = [dateCache allKeys];
for (i = 0; i < [allKeys count]; i++)
{
key = [allKeys objectAtIndex: i];
if ([[dateCache objectForKey:key] compare: theFilter ] == NSOrderedAscending)
[sdUids addObject: [dateCache objectForKey:key]];
}
}
return [sdUids count];
}
- (id) globallyUniqueIDToIMAPFolderName: (NSString *) theIdToTranslate
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType
{
@ -919,6 +955,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
sortOrdering: @"REVERSE ARRIVAL"
threaded: NO];
count = [uids count];
// Add the number of UIDs expected to "soft delete"
count += [self _softDeleteCountWithFilter: filter collectionId: realCollectionId];
}
else
{
@ -1899,9 +1939,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
value = [theDocumentElement getElementsByTagName: @"ReplaceMime"];
// ReplaceMime isn't specified so we must NOT use the server copy
// ReplaceMime IS specified so we must NOT use the server copy
// but rather take the data as-is from the client.
if (![value count])
if ([value count])
{
[self processSendMail: theDocumentElement
inResponse: theResponse];
@ -1925,7 +1965,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NGMutableHashMap *map;
NGMimeFileData *fdata;
NSException *error;
id body;
id body, bodyFromSmartForward;
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
@ -1941,10 +1982,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
parser = [[NGMimeMessageParser alloc] init];
data = [[[[(id)[theDocumentElement getElementsByTagName: @"MIME"] lastObject] textValue] stringByDecodingBase64] dataUsingEncoding: NSUTF8StringEncoding];
messageFromSmartForward = [parser parsePartFromData: data];
RELEASE(parser);
// We create a new MIME multipart/mixed message. The first part will be the text part
// of our "smart forward" and the second part will be the message/rfc822 part of the
// "smart forwarded" message.
@ -1954,11 +1993,39 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
messageToSend = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
body = [[[NGMimeMultipartBody alloc] initWithPart: messageToSend] autorelease];
// First part
// First part - either a text/* or a multipart/*. If it's a multipart,
// we take the first part text/* part we see.
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: @"text/plain" forKey: @"content-type"];
bodyFromSmartForward = nil;
if ([[messageFromSmartForward body] isKindOfClass: [NGMimeMultipartBody class]])
{
NGMimeBodyPart *part;
NSArray *parts;
int i;
parts = [[messageFromSmartForward body] parts];
for (i = 0; i < [parts count]; i++)
{
part = [parts objectAtIndex: i];
if ([[[part contentType] type] isEqualToString: @"text"])
{
[map setObject: [[part contentType] stringValue] forKey: @"content-type"];
bodyFromSmartForward = [part body];
break;
}
}
}
else
{
[map setObject: [[messageFromSmartForward contentType] stringValue] forKey: @"content-type"];
bodyFromSmartForward = [messageFromSmartForward body];
}
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease];
[bodyPart setBody: [messageFromSmartForward body]];
[bodyPart setBody: bodyFromSmartForward];
[body addBodyPart: bodyPart];
// Second part

View File

@ -238,6 +238,8 @@ struct GlobalObjectId {
if (key)
{
NSString *s, *charset;
d = [[self fetchPlainTextParts] objectForKey: key];
encoding = [[self lookupInfoForBodyPart: key] objectForKey: @"encoding"];
@ -246,6 +248,14 @@ struct GlobalObjectId {
d = [d dataByDecodingBase64];
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
d = [d dataByDecodingQuotedPrintableTransferEncoding];
charset = [[[self lookupInfoForBodyPart: key] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"us-ascii";
s = [NSString stringWithData: d usingEncodingNamed: charset];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
return d;
@ -296,13 +306,13 @@ struct GlobalObjectId {
if ([body isKindOfClass: [NSData class]])
{
NSString *charset;
int encoding;
charset = [[thePart contentType] valueOfParameter: @"charset"];
encoding = [NGMimeType stringEncodingForCharset: charset];
s = [[NSString alloc] initWithData: body encoding: encoding];
AUTORELEASE(s);
if (![charset length])
charset = @"us-ascii";
s = [NSString stringWithData: body usingEncodingNamed: charset];
}
else
{
@ -396,6 +406,13 @@ struct GlobalObjectId {
{
if ([type isEqualToString: @"text"])
{
NSString *s, *charset;
charset = [[[self lookupInfoForBodyPart: @""] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"us-ascii";
d = [[self fetchPlainTextParts] objectForKey: @""];
// We check if we have base64 encoded parts. If so, we just
@ -407,17 +424,15 @@ struct GlobalObjectId {
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
d = [d dataByDecodingQuotedPrintableTransferEncoding];
s = [NSString stringWithData: d usingEncodingNamed: charset];
// Check if we must convert html->plain
if (theType == 1 && [subtype isEqualToString: @"html"])
{
NSString *s;
s = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding];
AUTORELEASE(s);
s = [s htmlToText];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
else if ([type isEqualToString: @"multipart"])
{

8
NEWS
View File

@ -5,11 +5,19 @@ Enhancements
- contacts photos are now synchronized using ActiveSync (#2807)
- implemented the GetAttachment ActiveSync command (#2808)
- implemented the Ping ActiveSync command
- added "soft deletes" support for ActiveSync (#2734)
Bug fixes
- better handling of empty "Flag" messages over ActiveSync (#2806)
- fixed Chinese charset handling (#2809)
- fixed folder name (calendars and contacts) of new subscriptions (#2801)
- fixed the reply/forward operation over ActiveSync (#2805)
- fixed regression when attaching files to a reply
- wait 20 seconds (instead of 2) before deleting temporary download forms (#2811)
- avoid raising exceptions when the db is down and we try to access the preferences module (#2813)
- we now ignore the SCHEDULE-AGENT property when Thunderbird/Ligthning sends it to avoid
not-generating invitation responses for externally received IMIP messages
- improved charset handling over ActiveSync (#2810)
2.2.5 (2014-06-05)
------------------

View File

@ -232,7 +232,7 @@ static NSArray *privilegedTagNames = nil;
}
- (void) characters: (unichar *) _chars
length: (int) _len
length: (NSUInteger) _len
{
if (_len && _chars)
{

View File

@ -217,10 +217,10 @@
printf("</%s>\n", [_localName cString]);
}
- (void)characters:(unichar *)_chars length:(int)_len {
- (void)characters:(unichar *)_chars length:(NSUInteger)_len {
NSString *str;
id tmp;
unsigned i, len;
NSUInteger i, len;
if (_len == 0) {
[self indent];
@ -228,7 +228,7 @@
return;
}
for (i = 0; i < (unsigned)_len; i++) {
for (i = 0; i < _len; i++) {
if (_chars[i] > 255) {
NSLog(@"detected large char: o%04o d%03i h%04X",
_chars[i], _chars[i], _chars[i]);
@ -246,7 +246,7 @@
[self indent];
printf("\"%s\"\n", [str cString]);
}
- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
- (void)ignorableWhitespace:(unichar *)_chars length:(NSUInteger)_len {
NSString *data;
id tmp;

View File

@ -80,6 +80,8 @@ typedef enum {
- (NSArray *) calendarUIDs;
- (NSNumber *) activeTasks;
/* vevent UID handling */
- (NSString *) resourceNameForEventUID: (NSString *) _uid;

View File

@ -230,6 +230,8 @@ static iCalEvent *iCalEventK = nil;
abstract: NO
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
/* read-acl and write-acl are defined in RFC3744 */
[aclManager registerDAVPermission: davElement (@"admin", nsI)
abstract: YES
withEquivalent: nil
@ -242,6 +244,72 @@ static iCalEvent *iCalEventK = nil;
abstract: YES
withEquivalent: SoPerm_ChangePermissions
asChildOf: davElement (@"admin", nsI)];
/* Default permissions for calendars. These are very important so that DAV client can
detect permission changes on calendars and reload all items, if necessary */
/* Public ones */
[aclManager registerDAVPermission: davElement (@"viewwhole-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewWholePublicRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"viewdant-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewDAndTOfPublicRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"modify-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ModifyPublicRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"respondto-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_RespondToPublicRecords
asChildOf: davElement (@"admin", nsI)];
/* Private ones */
[aclManager registerDAVPermission: davElement (@"viewwhole-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewWholePrivateRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"viewdant-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewDAndTOfPrivateRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"modify-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ModifyPrivateRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"respondto-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_RespondToPrivateRecords
asChildOf: davElement (@"admin", nsI)];
/* Condifential ones */
[aclManager registerDAVPermission: davElement (@"viewwhole-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewWholeConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"viewdant-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewDAndTOfConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"modify-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ModifyConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"respondto-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_RespondToConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
}
return aclManager;
@ -522,7 +590,6 @@ static iCalEvent *iCalEventK = nil;
{
/* this is used for group calendars (this folder just returns itself) */
NSString *s;
s = [[self container] nameInContainer];
// [self logWithFormat:@"CAL UID: %@", s];
return [s isNotNull] ? [NSArray arrayWithObjects:&s count:1] : nil;
@ -3270,4 +3337,25 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return users;
}
- (NSNumber *) activeTasks
{
NSArray *tasksList;
NSMutableArray *fields;
NSNumber *activeTasks;
fields = [NSMutableArray arrayWithObjects: @"c_component", @"c_status", nil];
tasksList = [self bareFetchFields: fields
from: nil
to: nil
title: nil
component: @"vtodo"
additionalFilters: @"c_status != 1 AND c_status != 3"];
activeTasks = [NSNumber numberWithInt:[tasksList count]];
return activeTasks;
}
@end /* SOGoAppointmentFolder */

View File

@ -1428,8 +1428,10 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
//
- (BOOL) _shouldScheduleEvent: (iCalPerson *) theOrganizer
{
NSArray *userAgents;
NSString *v;
BOOL b;
int i;
b = YES;
@ -1440,6 +1442,27 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
b = NO;
}
//
// If we have to deal with Thunderbird/Lightning, we always send invitation
// reponses, as Lightning v2.6 (at least this version) sets SCHEDULE-AGENT
// to NONE/CLIENT when responding to an external invitation received by
// SOGo - so no invitation responses are ever sent by Lightning. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=865726 and
// https://bugzilla.mozilla.org/show_bug.cgi?id=997784
//
userAgents = [[context request] headersForKey: @"User-Agent"];
for (i = 0; i < [userAgents count]; i++)
{
if ([[userAgents objectAtIndex: i] rangeOfString: @"Thunderbird"].location != NSNotFound &&
[[userAgents objectAtIndex: i] rangeOfString: @"Lightning"].location != NSNotFound)
{
b = YES;
break;
}
}
return b;
}

View File

@ -430,7 +430,7 @@
}
- (void) ignorableWhitespace: (unichar *) whitespaces
length: (int) length
length: (NSUInteger) length
{
showWhoWeAre();
}

View File

@ -1764,16 +1764,16 @@ static NSString *userAgent = nil;
if ([ud mailAddOutgoingAddresses])
{
Class contactGCSEntry;
SOGoContactFolders *contactFolders;
NGMailAddressParser *parser;
id parsedRecipient;
SOGoContactFolder *folder;
SOGoContactGCSEntry *newContact;
NGVCard *card;
Class contactGCSEntry;
NGMailAddressParser *parser;
NSArray *matchingContacts;
NSMutableArray *recipients;
NSString *recipient, *emailAddress, *addressBook, *uid;
NSArray *matchingContacts;
id parsedRecipient;
int i;
// Get all the addressbooks

View File

@ -72,7 +72,7 @@
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR(255) PRIMARY KEY,"
@" c_parent_path VARCHAR(255),"
@" c_type TINYINT NOT NULL,"
@" c_type TINYINT UNSIGNED NOT NULL,"
@" c_creationdate INT NOT NULL,"
@" c_lastmodified INT NOT NULL,"
@" c_version INT NOT NULL DEFAULT 0,"

View File

@ -328,6 +328,10 @@ static NSArray *childRecordFields = nil;
= [[GCSFolderManager defaultFolderManager] folderInfoLocation];
fc = [cm acquireOpenChannelForURL: folderLocation];
if (fc)
{
// We use an exception handler here in case the database is down when
// performing the query. This could have unexpected results.
NS_DURING
{
sql
= [NSString stringWithFormat: (@"SELECT c_foldername FROM %@"
@ -341,6 +345,9 @@ static NSArray *childRecordFields = nil;
[fc cancelFetch];
[cm releaseChannel: fc];
}
NS_HANDLER;
NS_ENDHANDLER;
}
}
- (void) _fetchDisplayNameFromSubscriber

View File

@ -164,10 +164,12 @@ static SoSecurityManager *sm = nil;
NSString *folderName;
SOGoGCSFolder *folder;
SOGoUser *folderOwner;
SOGoUserDefaults *ud;
roles = [[context activeUser] rolesForObject: self inContext: context];
folderOwner = [SOGoUser userWithLogin: [self ownerInContext: context]];
// We autocreate the calendars if the user is the owner, a superuser or
// if it's a resource as we won't necessarily want to login as a resource
// in order to create its database tables.
@ -180,18 +182,27 @@ static SoSecurityManager *sm = nil;
folderName = @"personal";
folder = [subFolderClass objectWithName: folderName inContainer: self];
[folder setDisplayName: [self defaultFolderName]];
}
else if (folderType == SOGoCollectedFolder)
{
folderName = @"collected";
folder = [subFolderClass objectWithName: folderName inContainer: self];
[folder setDisplayName: [self collectedFolderName]];
}
[folder setOCSPath: [NSString stringWithFormat: @"%@/%@", OCSPath, folderName]];
if ([folder create])
[subFolders setObject: folder forKey: folderName];
}
else if (folderType == SOGoCollectedFolder)
{
ud = [[context activeUser] userDefaults];
if ([ud mailAddOutgoingAddresses]) {
folderName = @"collected";
folder = [subFolderClass objectWithName: folderName inContainer: self];
[folder setDisplayName: [self collectedFolderName]];
[folder setOCSPath: [NSString stringWithFormat: @"%@/%@", OCSPath, folderName]];
if ([folder create])
[subFolders setObject: folder forKey: folderName];
[ud setSelectedAddressBook:folderName];
}
}
}
}
- (NSException *) fetchSpecialFolders: (NSString *) sql

View File

@ -401,7 +401,17 @@ class DAVCalendarAclTest(DAVAclTest):
else:
expStatus = 207
privileges = self._currentUserPrivilegeSet(self.resource, expStatus)
self._comparePrivilegeSets(expectedPrivileges, privileges)
# When comparing privileges on DAV collection, we remove all 'default'
# privileges on the collection.
privileges_set = set(privileges);
for x in ("public", "private", "confidential"):
privileges_set.discard("{urn:inverse:params:xml:ns:inverse-dav}viewwhole-%s-records" % x)
privileges_set.discard("{urn:inverse:params:xml:ns:inverse-dav}viewdant-%s-records" % x)
privileges_set.discard("{urn:inverse:params:xml:ns:inverse-dav}modify-%s-records" % x)
privileges_set.discard("{urn:inverse:params:xml:ns:inverse-dav}respondto-%s-records" %x)
self._comparePrivilegeSets(expectedPrivileges, list(privileges_set))
def _testEventDAVAcl(self, event_class, right, error_code):
icsClass = self.classToICSClass[event_class].lower()

View File

@ -419,9 +419,9 @@ static NSData* _sanitizeContent(NSData *theData)
}
- (void) _appendStyle: (unichar *) _chars
length: (int) _len
length: (NSUInteger) _len
{
unsigned int count, length;
NSUInteger count, length;
unichar *start, *currentChar;
start = _chars;
@ -688,7 +688,7 @@ static NSData* _sanitizeContent(NSData *theData)
}
- (void) characters: (unichar *) _chars
length: (int) _len
length: (NSUInteger) _len
{
showWhoWeAre();
if (!ignoredContent)
@ -712,7 +712,7 @@ static NSData* _sanitizeContent(NSData *theData)
}
- (void) ignorableWhitespace: (unichar *) _chars
length: (int) _len
length: (NSUInteger) _len
{
showWhoWeAre();
}
@ -735,7 +735,7 @@ static NSData* _sanitizeContent(NSData *theData)
/* SaxLexicalHandler */
- (void) comment: (unichar *) _chars
length: (int) _len
length: (NSUInteger) _len
{
showWhoWeAre();
if (inStyle)

View File

@ -644,8 +644,9 @@ static NSArray *infoKeys = nil;
if (!attachmentAttrs || ![co imap4URL])
{
[co fetchInfo];
if (![co inReplyTo] && [co IMAP4ID] > -1)
if ((![co inReplyTo] || currentAttachment) && [co IMAP4ID] > -1)
{
// When currentAttachment is defined, it means we just attached a new file to the mail
mail = [[[SOGoMailObject alloc] initWithImap4URL: [co imap4URL] inContainer: [co container]] autorelease];
a = [mail fetchFileAttachmentKeys];
ASSIGN (attachmentAttrs, a);

View File

@ -723,7 +723,8 @@ static NSArray *reminderValues = nil;
count = [folders count]-1;
collectedAlreadyExist = NO;
for (i = 0; i <= count ; i++) {
for (i = 0; i <= count ; i++)
{
[availableAddressBooksID addObject:[[folders objectAtIndex:i] realNameInContainer]];
[availableAddressBooksName addObject:[[folders objectAtIndex:i] displayName]];
@ -732,8 +733,10 @@ static NSArray *reminderValues = nil;
}
// Create the dictionary for the next function : itemAddressBookText.
if (!addressBooksIDWithDisplayName)
{
addressBooksIDWithDisplayName = [[NSMutableDictionary alloc] initWithObjects:availableAddressBooksName
forKeys:availableAddressBooksID];
}
if (!collectedAlreadyExist)
{
[availableAddressBooksID addObject: @"collected"];
@ -742,6 +745,7 @@ static NSArray *reminderValues = nil;
return availableAddressBooksID;
}
- (NSString *) itemAddressBookText
{
return [addressBooksIDWithDisplayName objectForKey: item];

View File

@ -1,9 +1,6 @@
/* UIxCalListingActions.m - this file is part of SOGo
*
* Copyright (C) 2006-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
* Copyright (C) 2006-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
@ -484,7 +481,7 @@ static NSArray *tasksFields = nil;
return infos;
}
- (WOResponse *) _responseWithData: (NSArray *) data
- (WOResponse *) _responseWithData: (id) data
{
WOResponse *response;
@ -1282,4 +1279,28 @@ _computeBlocksPosition (NSArray *blocks)
return [self _responseWithData: filteredTasks];
}
- (WOResponse *) activeTasksAction
{
NSMutableDictionary *activeTasksByCalendars;
SOGoAppointmentFolder *folder;
SOGoAppointmentFolders *co;
NSArray *folders;
int i;
co = [self clientObject];
folders = [co subFolders];
activeTasksByCalendars = [NSMutableDictionary dictionaryWithCapacity: [folders count]];
for (i = 0; i < [folders count]; i++)
{
folder = [folders objectAtIndex: i];
[activeTasksByCalendars setObject: [folder activeTasks]
forKey: [folder nameInContainer]];
}
return [self _responseWithData: activeTasksByCalendars];
}
@end

View File

@ -93,7 +93,7 @@ _intValueFromHex (NSString *hexString)
NSMutableDictionary *calendar;
unsigned int count, max;
NSString *folderName, *fDisplayName;
NSNumber *isActive;
NSNumber *isActive, *fActiveTasks;
if (!calendars)
{
@ -120,6 +120,8 @@ _intValueFromHex (NSString *hexString)
[calendar setObject: isActive forKey: @"active"];
[calendar setObject: [folder ownerInContext: context]
forKey: @"owner"];
fActiveTasks = [folder activeTasks];
[calendar setObject:fActiveTasks forKey:@"activeTasks" ];
[calendars addObject: calendar];
}
}

View File

@ -94,6 +94,11 @@
actionClass = "UIxCalListingActions";
actionName = "tasksList";
};
activeTasks = {
protectedBy = "View";
actionClass = "UIxCalListingActions";
actionName = "activeTasks";
};
dayview = {
protectedBy = "View";
pageName = "UIxCalDayView";

View File

@ -299,7 +299,8 @@
<dd><input type="checkbox"
const:name="addOutgoingAddresses"
const:id="addOutgoingAddresses"
var:checked="addOutgoingAddresses" />
var:checked="addOutgoingAddresses"
onChange = "onAddOutgoingAddressesCheck(this);"/>
<var:string label:value="When sending mail, add unknown recipients to my"/><br/>
<var:popup list="addressBookList" item="item"
const:id="addressBookList"

View File

@ -38,9 +38,10 @@ div.colorBox.calendarFolder<var:string value="currentCalendar.folder" />
<var:foreach list="calendars" item="currentCalendar"
><li class="denied" var:id="currentCalendar.id" var:owner="currentCalendar.owner" >
<input type="checkbox" class="checkBox" const:disabled="disabled" var:checked="currentCalendar.active" />
<div var:class="currentCalendarClass"><entity name="nbsp"/></div
><var:string value="currentCalendar.displayName"
/></li>
<div var:class="currentCalendarClass"><entity name="nbsp"/></div>
<var:string value="currentCalendar.displayName" />
<span id="activeTasks"><var:string value="currentCalendar.activeTasks"/></span>
</li>
</var:foreach>
</ul>
</div>

View File

@ -1749,7 +1749,7 @@ function download(url) {
setTimeout(function () {
form.remove();
div.remove();
}, 2000);
}, 20000);
}
function saveAttachment(event) {

View File

@ -1102,6 +1102,30 @@ function eventsListCallback(http) {
log ("eventsListCallback Ajax error");
}
function activeTasksCallback(http) {
if (http.readyState == 4 && http.status == 200) {
if (http.responseText.length > 0) {
var data = http.responseText.evalJSON(true);
var list = $("calendarList");
var items = list.childNodesWithTag("li");
for (var i = 0; i < items.length; i++) {
var id = items[i].getAttribute("id").substr(1);
var number = data[id];
var input = items[i].childNodesWithTag("input")[0];
var activeTasks = items[i].childNodesWithTag("span")[0];
$(input).observe("click", clickEventWrapper(updateCalendarStatus));
if (number == "0") {
activeTasks.innerHTML = "";
}
else {
activeTasks.innerHTML = "(" + number + ")";
}
}
}
}
}
function tasksListCallback(http) {
if (http.readyState == 4
&& http.status == 200) {
@ -2336,6 +2360,7 @@ function _loadTasksHref(href) {
document.tasksListAjaxRequest.abort();
}
url = ApplicationBaseURL + "/" + href;
urlActiveTasks = ApplicationBaseURL + "/activeTasks";
var tasksList = $("tasksList");
var selectedIds;
@ -2343,8 +2368,10 @@ function _loadTasksHref(href) {
selectedIds = tasksList.getSelectedNodesId();
else
selectedIds = null;
document.tasksListAjaxRequest
= triggerAjaxRequest(url, tasksListCallback, selectedIds);
document.tasksListAjaxRequest = triggerAjaxRequest(url, tasksListCallback, selectedIds);
triggerAjaxRequest(urlActiveTasks, activeTasksCallback);
return true;
}
@ -3051,7 +3078,15 @@ function initCalendarSelector() {
var items = list.childNodesWithTag("li");
for (var i = 0; i < items.length; i++) {
var input = items[i].childNodesWithTag("input")[0];
var activeTasks = items[i].childNodesWithTag("span")[0];
$(input).observe("click", clickEventWrapper(updateCalendarStatus));
if (activeTasks.textContent == "0") {
activeTasks.innerHTML = "";
}
else {
activeTasks.innerHTML = "(" + activeTasks.innerText + ")";
}
}
var links = $("calendarSelectorButtons").childNodesWithTag("a");

View File

@ -291,6 +291,7 @@ function initPreferences() {
$("vacationEndDate_date").disable();
});
}
onAddOutgoingAddressesCheck();
}
function initSieveFilters() {
@ -1173,6 +1174,13 @@ function serializeContactsCategories() {
/* / contact categories */
function onAddOutgoingAddressesCheck(checkBox) {
if (!checkBox) {
checkBox = $("addOutgoingAddresses");
}
$("addressBookList").disabled = !checkBox.checked;
}
function onReplyPlacementListChange() {
if ($("replyPlacementList").value == 0) {