diff --git a/ActiveSync/GNUmakefile b/ActiveSync/GNUmakefile index 12f12e56b..969580670 100644 --- a/ActiveSync/GNUmakefile +++ b/ActiveSync/GNUmakefile @@ -9,6 +9,7 @@ ActiveSync_PRINCIPAL_CLASS = ActiveSyncProduct ActiveSync_OBJC_FILES = \ ActiveSyncProduct.m \ + iCalAlarm+ActiveSync.m \ iCalEvent+ActiveSync.m \ iCalRecurrenceRule+ActiveSync.m \ iCalTimeZone+ActiveSync.m \ @@ -30,7 +31,7 @@ ActiveSync_RESOURCE_FILES += \ ADDITIONAL_OBJCFLAGS += -Wno-deprecated-declarations ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/ -ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/ +ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/ ADDITIONAL_INCLUDE_DIRS += -I/usr/include/libwbxml-1.0/ ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -lwbxml2 diff --git a/ActiveSync/SOGoActiveSyncDispatcher.m b/ActiveSync/SOGoActiveSyncDispatcher.m index 67fdc7e37..7d99cebc5 100644 --- a/ActiveSync/SOGoActiveSyncDispatcher.m +++ b/ActiveSync/SOGoActiveSyncDispatcher.m @@ -868,105 +868,116 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. { NSString *srcMessageId, *srcFolderId, *dstFolderId, *dstMessageId; SOGoMicrosoftActiveSyncFolderType srcFolderType, dstFolderType; + id aMoveOperation; + NSArray *moveOperations; + NSMutableString *s; + NSData *d; + int i; - srcMessageId = [[(id)[theDocumentElement getElementsByTagName: @"SrcMsgId"] lastObject] textValue]; - srcFolderId = [[[(id)[theDocumentElement getElementsByTagName: @"SrcFldId"] lastObject] textValue] realCollectionIdWithFolderType: &srcFolderType]; - dstFolderId = [[[(id)[theDocumentElement getElementsByTagName: @"DstFldId"] lastObject] textValue] realCollectionIdWithFolderType: &dstFolderType]; + moveOperations = (id)[theDocumentElement getElementsByTagName: @"Move"]; + + s = [NSMutableString string]; - // FIXME - if (srcFolderType == ActiveSyncMailFolder && dstFolderType == ActiveSyncMailFolder) + [s appendString: @""]; + [s appendString: @""]; + [s appendString: @""]; + + for (i = 0; i < [moveOperations count]; i++) { - NGImap4Client *client; - id currentCollection; - - NSDictionary *response; - NSString *v; + aMoveOperation = [moveOperations objectAtIndex: i]; - currentCollection = [self collectionFromId: srcFolderId type: srcFolderType]; + srcMessageId = [[(id)[aMoveOperation getElementsByTagName: @"SrcMsgId"] lastObject] textValue]; + srcFolderId = [[[(id)[aMoveOperation getElementsByTagName: @"SrcFldId"] lastObject] textValue] realCollectionIdWithFolderType: &srcFolderType]; + dstFolderId = [[[(id)[aMoveOperation getElementsByTagName: @"DstFldId"] lastObject] textValue] realCollectionIdWithFolderType: &dstFolderType]; + + [s appendString: @""]; - // [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", srcFolderId] - // inContext: context - // acquire: NO]; - - client = [[currentCollection imap4Connection] client]; - [client select: srcFolderId]; - response = [client copyUid: [srcMessageId intValue] - toFolder: [NSString stringWithFormat: @"/%@", dstFolderId]]; - - // We extract the destionation message id - dstMessageId = nil; - - if ([[response objectForKey: @"result"] boolValue] - && (v = [[[response objectForKey: @"RawResponse"] objectForKey: @"ResponseResult"] objectForKey: @"flag"]) - && [v hasPrefix: @"COPYUID "]) + // FIXME - we should support moving events between calendars, for example, or + // or contacts between address books. + if (srcFolderType == ActiveSyncMailFolder && dstFolderType == ActiveSyncMailFolder) { - dstMessageId = [[v componentsSeparatedByString: @" "] lastObject]; + NGImap4Client *client; + id currentCollection; + + NSDictionary *response; + NSString *v; + + currentCollection = [self collectionFromId: srcFolderId type: srcFolderType]; + + client = [[currentCollection imap4Connection] client]; + [client select: srcFolderId]; + response = [client copyUid: [srcMessageId intValue] + toFolder: [NSString stringWithFormat: @"/%@", dstFolderId]]; + + // We extract the destionation message id + dstMessageId = nil; + + if ([[response objectForKey: @"result"] boolValue] + && (v = [[[response objectForKey: @"RawResponse"] objectForKey: @"ResponseResult"] objectForKey: @"flag"]) + && [v hasPrefix: @"COPYUID "]) + { + dstMessageId = [[v componentsSeparatedByString: @" "] lastObject]; + + // We mark the original message as deleted + response = [client storeFlags: [NSArray arrayWithObject: @"Deleted"] + forUIDs: [NSArray arrayWithObject: srcMessageId] + addOrRemove: YES]; + + if ([[response valueForKey: @"result"] boolValue]) + [(SOGoMailFolder *)currentCollection expunge]; + + } + + if (!dstMessageId) + { + // FIXME: should we return 1 or 2 here? + [s appendFormat: @"%d", 2]; + } + else + { + // + // If the MoveItems operation is initiated by an Outlook client, we save the "deviceType+dstMessageId" to use it later in order to + // modify the Sync command from "add" to "change" (see SOGoActiveSyncDispatcher+Sync.m: -processSyncGetChanges: ...). + // This is to avoid Outlook creating dupes when moving messages across folfers. + // + if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"]) + { + NSString *key; + + // The key must be pretty verbose. We use the +++ + key = [NSString stringWithFormat: @"%@+%@+%@+%@", + [[context activeUser] login], + [context objectForKey: @"DeviceType"], + dstFolderId, + dstMessageId]; + + + [[SOGoCache sharedCache] setValue: @"MovedItem" + forKey: key]; + } + + // Everything is alright, lets return the proper response. "Status == 3" means success. + [s appendFormat: @"%@", srcMessageId]; + [s appendFormat: @"%@", dstMessageId]; + [s appendFormat: @"%d", 3]; + } - // We mark the original message as deleted - response = [client storeFlags: [NSArray arrayWithObject: @"Deleted"] - forUIDs: [NSArray arrayWithObject: srcMessageId] - addOrRemove: YES]; - - if ([[response valueForKey: @"result"] boolValue]) - [(SOGoMailFolder *)currentCollection expunge]; - - } - - if (!dstMessageId) - { - [theResponse setStatus: 500]; - [theResponse appendContentString: @"Unable to move message"]; } else { - NSMutableString *s; - NSData *d; - - // - // If the MoveItems operation is initiated by an Outlook client, we save the "deviceType+dstMessageId" to use it later in order to - // modify the Sync command from "add" to "change" (see SOGoActiveSyncDispatcher+Sync.m: -processSyncGetChanges: ...). - // This is to avoid Outlook creating dupes when moving messages across folfers. - // - if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"]) - { - NSString *key; - - // The key must be pretty verbose. We use the +++ - key = [NSString stringWithFormat: @"%@+%@+%@+%@", - [[context activeUser] login], - [context objectForKey: @"DeviceType"], - dstFolderId, - dstMessageId]; - - - [[SOGoCache sharedCache] setValue: @"MovedItem" - forKey: key]; - } - - - // Everything is alright, lets return the proper response. "Status == 3" means success. - s = [NSMutableString string]; - - [s appendString: @""]; - [s appendString: @""]; - [s appendString: @""]; - [s appendString: @""]; - [s appendFormat: @"%@", srcMessageId]; - [s appendFormat: @"%@", dstMessageId]; - [s appendFormat: @"%d", 3]; - [s appendString: @""]; - [s appendString: @""]; - - d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml]; - - [theResponse setContent: d]; + // Non-mail move operations - unsupported for now. + [s appendFormat: @"%d", 1]; } + + [s appendString: @""]; } - else - { - [theResponse setStatus: 500]; - [theResponse appendContentString: @"Unsupported move operation"]; - } + + + [s appendString: @""]; + + d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml]; + + [theResponse setContent: d]; } // diff --git a/ActiveSync/SOGoMailObject+ActiveSync.m b/ActiveSync/SOGoMailObject+ActiveSync.m index f2d1c792c..05f448df3 100644 --- a/ActiveSync/SOGoMailObject+ActiveSync.m +++ b/ActiveSync/SOGoMailObject+ActiveSync.m @@ -762,6 +762,16 @@ struct GlobalObjectId { // // // +// Exemple for a message being marked as read: +// +// +// 607 +// +// 1 +// +// +// +// - (void) takeActiveSyncValues: (NSDictionary *) theValues inContext: (WOContext *) _context { @@ -776,6 +786,14 @@ struct GlobalObjectId { else [self removeFlags: @"\\Flagged"]; } + + if ((o = [theValues objectForKey: @"Read"])) + { + if ([o intValue]) + [self addFlags: @"seen"]; + else + [self removeFlags: @"seen"];; + } } @end diff --git a/ActiveSync/common.make b/ActiveSync/common.make index 78ad58bd1..d53fcef8e 100644 --- a/ActiveSync/common.make +++ b/ActiveSync/common.make @@ -1,5 +1,3 @@ -# common make file for SoObject bundles - include ../config.make include $(GNUSTEP_MAKEFILES)/common.make include ../Version @@ -18,10 +16,10 @@ ADDITIONAL_INCLUDE_DIRS += \ -I../../SOPE ADDITIONAL_LIB_DIRS += \ - -L../SOGo/SOGo.framework/ \ - -L../../SOGo/$(GNUSTEP_OBJ_DIR)/ \ - -L../../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \ - -L../../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \ + -L../SoObjects/SOGo/SOGo.framework/ \ + -L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \ + -L../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \ + -L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \ -L/usr/local/lib BUNDLE_LIBS += \ diff --git a/ActiveSync/iCalAlarm+ActiveSync.h b/ActiveSync/iCalAlarm+ActiveSync.h new file mode 100644 index 000000000..838c5042c --- /dev/null +++ b/ActiveSync/iCalAlarm+ActiveSync.h @@ -0,0 +1,46 @@ +/* + +Copyright (c) 2014, Inverse inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Inverse inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ +#ifndef __ICALALARMACTIVESYNC_H__ +#define __ICALALARMACTIVESYNC_H__ + +#import + +@class NSString; +@class WOContext; + +@interface iCalAlarm (ActiveSync) + +- (NSString *) activeSyncRepresentationInContext: (WOContext *) context; +- (void) takeActiveSyncValues: (NSDictionary *) theValues + inContext: (WOContext *) context; + +@end + +#endif diff --git a/ActiveSync/iCalAlarm+ActiveSync.m b/ActiveSync/iCalAlarm+ActiveSync.m new file mode 100644 index 000000000..33e6dbb73 --- /dev/null +++ b/ActiveSync/iCalAlarm+ActiveSync.m @@ -0,0 +1,106 @@ +/* + +Copyright (c) 2014, Inverse inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Inverse inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ +#import "iCalAlarm+ActiveSync.h" + +#import +#import + +#import +#import +#import + +#import +#import +#import + +@implementation iCalAlarm (ActiveSync) + +- (NSString *) activeSyncRepresentationInContext: (WOContext *) context +{ + NSMutableString *s; + + s = [NSMutableString string]; + + if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame) + { + NSCalendarDate *nextAlarmDate; + NSInteger delta; + + nextAlarmDate = [self nextAlarmDate]; + delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60); + + // don't send negative reminder - not supported + if (delta > 0) + [s appendFormat: @"%d", delta]; + } + + return s; +} + +- (void) takeActiveSyncValues: (NSDictionary *) theValues + inContext: (WOContext *) context +{ + iCalTrigger *trigger; + id o; + + o = [theValues objectForKey: @"Reminder"]; + + // Outlook: if reminder is set to 0 minutes before start save it as 1 minute since -> 0 minutes in not accepted by SOGo + if ([o isEqualToString: @"0"]) + o = @"1"; + + trigger = [iCalTrigger elementWithTag: @"TRIGGER"]; + [trigger setValueType: @"DURATION"]; + [self setTrigger: trigger]; + [self setAction: @"DISPLAY"]; + + // SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days) + // 1week = -P1W + // 2weeks > -PxD + // xdays > -PxD + // xhours -> -PTxH + // xmin -> -PTxM + if ([o intValue] == 10080) + [trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""]; + else + { + if (([o intValue] % 1440) == 0) + [trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""]; + else + { + if (([o intValue] % 60) == 0) + [trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""]; + else + [trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""]; + } + } +} + +@end diff --git a/ActiveSync/iCalEvent+ActiveSync.m b/ActiveSync/iCalEvent+ActiveSync.m index 05f18a3ce..8b15a6d8d 100644 --- a/ActiveSync/iCalEvent+ActiveSync.m +++ b/ActiveSync/iCalEvent+ActiveSync.m @@ -50,6 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import +#include "iCalAlarm+ActiveSync.h" #include "iCalRecurrenceRule+ActiveSync.h" #include "iCalTimeZone+ActiveSync.h" #include "NSDate+ActiveSync.h" @@ -83,6 +84,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. int v; + NSTimeZone *userTimeZone; + userTimeZone = [[[context activeUser] userDefaults] timeZone]; + s = [NSMutableString string]; [s appendFormat: @"%d", ([self isAllDay] ? 1 : 0)]; @@ -95,12 +99,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx if ([self startDate]) - [s appendFormat: @"%@", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]]; - + { + if ([self isAllDay]) + [s appendFormat: @"%@", + [[[self startDate] dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: ([userTimeZone secondsFromGMTForDate: [self startDate]])*-1] + activeSyncRepresentationWithoutSeparatorsInContext: context]]; + else + [s appendFormat: @"%@", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]]; + } + // EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx if ([self endDate]) - [s appendFormat: @"%@", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]]; - + { + if ([self isAllDay]) + [s appendFormat: @"%@", + [[[self endDate] dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: ([userTimeZone secondsFromGMTForDate: [self endDate]])*-1] + activeSyncRepresentationWithoutSeparatorsInContext: context]]; + else + [s appendFormat: @"%@", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]]; + } + // Timezone tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone]; @@ -209,7 +231,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [s appendFormat: @"%d", v]; // Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx - // TODO + // TODO: improve this to handle more alarm types + if ([self hasAlarms]) + { + iCalAlarm *alarm; + + alarm = [[self alarms] objectAtIndex: 0]; + [s appendString: [alarm activeSyncRepresentationInContext: context]]; + } // Recurrence rules if ([self isRecurrent]) @@ -356,6 +385,10 @@ 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]; [start setDate: o]; [start setTimeZone: nil]; } @@ -377,6 +410,10 @@ 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]; } @@ -390,6 +427,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } } + // + // If an alarm is deinfed with an action != DISPLAY, we ignore the alarm - don't want to overwrite. + // + if ([self hasAlarms] && [[[[self alarms] objectAtIndex: 0] action] caseInsensitiveCompare: @"DISPLAY"] != NSOrderedSame) + { + // Ignore the alarm for now + } + else if ((o = [theValues objectForKey: @"Reminder"])) + { + // NOTE: Outlook sends a 15 min reminder (18 hour for allday) if no reminder is specified + // although no default reminder is defined (File -> Options -> Clendar -> Calendar Options - > Default Reminders) + // + // http://answers.microsoft.com/en-us/office/forum/office_2013_release-outlook/desktop-outlook-calendar-creates-entries-with/9aef72d8-81bb-4a32-a6ab-bf7d216fb811?page=5&tm=1395690285088 + // + iCalAlarm *alarm; + + alarm = [[iCalAlarm alloc] init]; + [alarm takeActiveSyncValues: theValues inContext: context]; + + [self removeAllAlarms]; + [self addToAlarms: alarm]; + RELEASE(alarm); + } + else + { + // We remove existing alarm since no reminder in the ActiveSync payload + [self removeAllAlarms]; + } + // Recurrence if ((o = [theValues objectForKey: @"Recurrence"])) { diff --git a/ChangeLog b/ChangeLog index efd04f6c1..d984d6bab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,202 @@ +commit 370e1e6d266a84eb089ccf33b14e0902ecee7fff +Author: Francis Lachapelle +Date: Thu Apr 3 10:01:01 2014 -0400 + + Update CKEditor to version 4.3.4 + +M NEWS +M UI/WebServerResources/ckeditor/build-config.js +M UI/WebServerResources/ckeditor/ckeditor.js +M UI/WebServerResources/ckeditor/lang/ar.js +M UI/WebServerResources/ckeditor/lang/ca.js +M UI/WebServerResources/ckeditor/lang/cs.js +M UI/WebServerResources/ckeditor/lang/cy.js +M UI/WebServerResources/ckeditor/lang/da.js +M UI/WebServerResources/ckeditor/lang/de.js +M UI/WebServerResources/ckeditor/lang/en.js +M UI/WebServerResources/ckeditor/lang/es.js +M UI/WebServerResources/ckeditor/lang/fi.js +M UI/WebServerResources/ckeditor/lang/fr.js +M UI/WebServerResources/ckeditor/lang/hu.js +M UI/WebServerResources/ckeditor/lang/is.js +M UI/WebServerResources/ckeditor/lang/it.js +M UI/WebServerResources/ckeditor/lang/nb.js +M UI/WebServerResources/ckeditor/lang/nl.js +M UI/WebServerResources/ckeditor/lang/no.js +M UI/WebServerResources/ckeditor/lang/pl.js +M UI/WebServerResources/ckeditor/lang/pt-br.js +M UI/WebServerResources/ckeditor/lang/ru.js +M UI/WebServerResources/ckeditor/lang/sk.js +M UI/WebServerResources/ckeditor/lang/sv.js +M UI/WebServerResources/ckeditor/lang/uk.js +M UI/WebServerResources/ckeditor/plugins/icons.png +M UI/WebServerResources/ckeditor/plugins/icons_hidpi.png +A UI/WebServerResources/ckeditor/plugins/scayt/LICENSE.md +A UI/WebServerResources/ckeditor/plugins/wsc/LICENSE.md +M UI/WebServerResources/ckeditor/skins/moono/editor.css +M UI/WebServerResources/ckeditor/skins/moono/editor_gecko.css +M UI/WebServerResources/ckeditor/skins/moono/editor_ie.css +M UI/WebServerResources/ckeditor/skins/moono/editor_ie7.css +M UI/WebServerResources/ckeditor/skins/moono/editor_ie8.css +M UI/WebServerResources/ckeditor/skins/moono/editor_iequirks.css +M UI/WebServerResources/ckeditor/skins/moono/icons.png +M UI/WebServerResources/ckeditor/skins/moono/icons_hidpi.png + +commit e2b3d5a7ffd9bc6cab97f973145f335169b708af +Author: Francis Lachapelle +Date: Thu Apr 3 09:54:27 2014 -0400 + + Update translations + +M NEWS +M SoObjects/Mailer/Dutch.lproj/Localizable.strings +M SoObjects/Mailer/Hungarian.lproj/Localizable.strings +M SoObjects/Mailer/Russian.lproj/Localizable.strings +M UI/Common/Hungarian.lproj/Localizable.strings +M UI/MailerUI/Dutch.lproj/Localizable.strings +M UI/Scheduler/SpanishArgentina.lproj/Localizable.strings + +commit 078b88a396b3839880e6cc3638e5d2f6307c670c +Author: Ludovic Marcotte +Date: Wed Apr 2 18:14:17 2014 -0400 + + Fix for #2686 + +M ActiveSync/iCalEvent+ActiveSync.m +M NEWS + +commit ee09b80fc37f51907606e6e3c516b3ebad9cfece +Author: Francis Lachapelle +Date: Wed Apr 2 10:15:59 2014 -0400 + + Simplify [UIxContactEditor addressBookDisplayName] + + We were trying to translate the default address book name to the user's + language, but the method [SOGoContactFolders defaultFolderName] is + already returning a translated string, making the whole logic useless. + +M UI/Contacts/UIxContactEditor.m + +commit 99d9615c929fcee7454736a9a1f4850a50139225 +Author: Francis Lachapelle +Date: Wed Apr 2 10:09:09 2014 -0400 + + Update NEWS file + +M NEWS + +commit ce5d591d1de7c2a09b0cfaf4b47e3aeca4464e77 +Author: opensaucesystems +Date: Tue Apr 1 12:35:18 2014 +0100 + + Fix email validation regexp to allow gTLDs + + New generic TLDs can be as long as 13 characters. + +M UI/WebServerResources/generic.js + +commit e603742d71fabd99595151a31fbd1159e9d861c5 +Author: Jeroen Dekkers +Date: Sat Mar 29 17:11:05 2014 +0100 + + Remove executable permission from jQuery + +M UI/WebServerResources/jquery-ui.js +M UI/WebServerResources/jquery.fileupload.css +M UI/WebServerResources/jquery.fileupload.js +M UI/WebServerResources/jquery.iframe-transport.js + +commit 585d224a153bda4f1aebde1de3fb59266898168e +Author: Ludovic Marcotte +Date: Fri Mar 28 16:44:33 2014 -0400 + + Fixed the AS bundle common makefile + +M ActiveSync/common.make + +commit 6a39b48a37956a35ae581f5fd31dd8a6c6e152fa +Author: Ludovic Marcotte +Date: Fri Mar 28 15:22:45 2014 -0400 + + Fix for bug #2691 + +M ActiveSync/SOGoActiveSyncDispatcher.m +M NEWS + +commit 633723a4708db1a807c69aae8204a39213941b54 +Author: Ludovic Marcotte +Date: Fri Mar 28 14:44:00 2014 -0400 + + Fix for bug #2681 + +M ActiveSync/GNUmakefile +A ActiveSync/iCalAlarm+ActiveSync.h +A ActiveSync/iCalAlarm+ActiveSync.m +M ActiveSync/iCalEvent+ActiveSync.m +M NEWS + +commit ba32b95308c8cff3521752cbc6088bc7e5c05425 +Author: Ludovic Marcotte +Date: Fri Mar 28 14:18:48 2014 -0400 + + Fixed the ActiveSync issue marking mails as read when downloading them + +M ActiveSync/SOGoMailObject+ActiveSync.m +M NEWS +M SoObjects/Mailer/SOGoMailBaseObject.m +M SoObjects/Mailer/SOGoMailObject.m +M UI/WebServerResources/MailerUI.js + +commit 6e4f776d4b7ede6acc9c54f4f1799858085b6b4c +Author: Francis Lachapelle +Date: Thu Mar 27 12:06:24 2014 -0400 + + Fix detection of IMAP flags support in JavaScript + + Fixes #2664 + +M NEWS +M UI/WebServerResources/UIxFilterEditor.js + +commit e5fb7dc7b8685102203a4071a5d381aa56382dc8 +Author: Francis Lachapelle +Date: Mon Mar 24 12:43:34 2014 -0400 + + Fix JavaScript exception in Contacts module + + Fixed calling unescapeHTML on null variables. Also fixed errors on IE7 + (and possibly other versions). + +M NEWS +M UI/WebServerResources/ContactsUI.js + +commit 50e7ea71883f641bd5ebd72ecdc8cdb8eb7862fa +Author: Francis Lachapelle +Date: Mon Mar 24 07:42:57 2014 -0400 + + Fix possible exception when retrieving reminder + + Fixes #2678 + +M NEWS +M UI/PreferencesUI/UIxPreferences.m + +commit 89e61f6d5d540b497b9999b517532cb1a18333d0 +Author: Ludovic Marcotte +Date: Fri Mar 21 15:37:14 2014 -0400 + + Fixed SOPE include path + +M ActiveSync/GNUmakefile + +commit 85f4af56e9738de3e70adadb78cf77f7712b2b53 +Author: Francis Lachapelle +Date: Fri Mar 21 15:22:28 2014 -0400 + + Update ChangeLog + +M ChangeLog + commit 04bdb22b00f5de7a5a399205ec91ba9de881076d Author: Francis Lachapelle Date: Fri Mar 21 15:20:45 2014 -0400 diff --git a/Documentation/SOGo Installation Guide.odt b/Documentation/SOGo Installation Guide.odt index 010be4806..fff970fae 100644 Binary files a/Documentation/SOGo Installation Guide.odt and b/Documentation/SOGo Installation Guide.odt differ diff --git a/Documentation/SOGo Mobile Devices Configuration.odt b/Documentation/SOGo Mobile Devices Configuration.odt index c4de95af9..401789ea8 100644 Binary files a/Documentation/SOGo Mobile Devices Configuration.odt and b/Documentation/SOGo Mobile Devices Configuration.odt differ diff --git a/Documentation/SOGo Mozilla Thunderbird Configuration.odt b/Documentation/SOGo Mozilla Thunderbird Configuration.odt index a425fe1d0..80006f295 100644 Binary files a/Documentation/SOGo Mozilla Thunderbird Configuration.odt and b/Documentation/SOGo Mozilla Thunderbird Configuration.odt differ diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 884eeb5ae..dd347b2d0 100644 Binary files a/Documentation/SOGo Native Microsoft Outlook Configuration.odt and b/Documentation/SOGo Native Microsoft Outlook Configuration.odt differ diff --git a/NEWS b/NEWS index 6350806a8..2ff80d636 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,20 @@ +2.2.3 (2014-04-03) +------------------ + +Enhancements + - updated Dutch, Hungarian, Russian and Spanish (Argentina) translations + - initial support for ActiveSync event reminders support (#2681) + - updated CKEditor to version 4.3.4 + +Bug fixes + - fixed possible exception when retrieving the default event reminder value on 64bit architectures (#2678) + - fixed calling unescapeHTML on null variables to avoid JavaScript exceptions in Contacts module + - fixed detection of IMAP flags support on the client side (#2664) + - fixed the ActiveSync issue marking all mails as read when downloading them + - fixed ActiveSync's move operations not working for multiple selections (#2691) + - fixed email validation regexp to allow gTLDs + - improved all-day events support for ActiveSync (#2686) + 2.2.2 (2014-03-21) ------------------ diff --git a/SoObjects/Mailer/Dutch.lproj/Localizable.strings b/SoObjects/Mailer/Dutch.lproj/Localizable.strings index 32280490f..c70b3b143 100644 --- a/SoObjects/Mailer/Dutch.lproj/Localizable.strings +++ b/SoObjects/Mailer/Dutch.lproj/Localizable.strings @@ -1,2 +1,2 @@ -"SieveFolderName" = "Berichtregel"; "OtherUsersFolderName" = "Andere Gebruikers"; +"SharedFoldersName" = "Gedeelde Mappen"; diff --git a/SoObjects/Mailer/Hungarian.lproj/Localizable.strings b/SoObjects/Mailer/Hungarian.lproj/Localizable.strings index 22b6c7ec7..b72e0b52c 100644 --- a/SoObjects/Mailer/Hungarian.lproj/Localizable.strings +++ b/SoObjects/Mailer/Hungarian.lproj/Localizable.strings @@ -1,2 +1,2 @@ -"SieveFolderName" = "Szűrők"; "OtherUsersFolderName" = "Egyéb felhasználók"; +"SharedFoldersName" = "Megosztott mappák"; diff --git a/SoObjects/Mailer/Russian.lproj/Localizable.strings b/SoObjects/Mailer/Russian.lproj/Localizable.strings index 81d857d7c..0a5a29276 100644 --- a/SoObjects/Mailer/Russian.lproj/Localizable.strings +++ b/SoObjects/Mailer/Russian.lproj/Localizable.strings @@ -1,2 +1,2 @@ -"SieveFolderName" = "Папки"; "OtherUsersFolderName" = "Другие пользователи"; +"SharedFoldersName" = "Общие папки"; diff --git a/SoObjects/Mailer/SOGoMailBaseObject.m b/SoObjects/Mailer/SOGoMailBaseObject.m index 62f3da511..73967efe0 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.m +++ b/SoObjects/Mailer/SOGoMailBaseObject.m @@ -1,14 +1,15 @@ /* + Copyright (C) 2007-2014 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG - 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. diff --git a/SoObjects/Mailer/SOGoMailObject.m b/SoObjects/Mailer/SOGoMailObject.m index 85eacf5b9..4ec55af30 100644 --- a/SoObjects/Mailer/SOGoMailObject.m +++ b/SoObjects/Mailer/SOGoMailObject.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2007-2009 Inverse inc. + Copyright (C) 2007-2014 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG This file is part of SOGo. @@ -434,7 +434,8 @@ static BOOL debugSoParts = NO; NSData *content; id result, fullResult; - fullResult = [self fetchParts: [NSArray arrayWithObject: @"RFC822"]]; + // We avoid using RFC822 here as the part name as it'll flag the message as Seen + fullResult = [self fetchParts: [NSArray arrayWithObject: @"BODY.PEEK[]"]]; if (fullResult == nil) return nil; @@ -458,7 +459,7 @@ static BOOL debugSoParts = NO; /* extract message */ - if ((content = [result valueForKey: @"message"]) == nil) { + if ((content = [[result valueForKey: @"body[]"] valueForKey: @"data"]) == nil) { [self logWithFormat: @"ERROR: unexpected IMAP4 result (missing 'message'): %@", result]; @@ -504,26 +505,6 @@ static BOOL debugSoParts = NO; } /* bulk fetching of plain/text content */ - -// - (BOOL) shouldFetchPartOfType: (NSString *) _type -// subtype: (NSString *) _subtype -// { -// /* -// This method decides which parts are 'prefetched' for display. Those are -// usually text parts (the set is currently hardcoded in this method ...). -// */ -// _type = [_type lowercaseString]; -// _subtype = [_subtype lowercaseString]; - -// return (([_type isEqualToString: @"text"] -// && ([_subtype isEqualToString: @"plain"] -// || [_subtype isEqualToString: @"html"] -// || [_subtype isEqualToString: @"calendar"])) -// || ([_type isEqualToString: @"application"] -// && ([_subtype isEqualToString: @"pgp-signature"] -// || [_subtype hasPrefix: @"x-vnd.kolab."]))); -// } - - (void) addRequiredKeysOfStructure: (NSDictionary *) info path: (NSString *) p toArray: (NSMutableArray *) keys @@ -623,9 +604,12 @@ static BOOL debugSoParts = NO; @"text/calendar", @"application/ics", @"application/pgp-signature", nil]; ma = [NSMutableArray arrayWithCapacity: 4]; + [self addRequiredKeysOfStructure: [self bodyStructure] - path: @"" toArray: ma acceptedTypes: types - withPeek: NO]; + path: @"" + toArray: ma + acceptedTypes: types + withPeek: YES]; return ma; } @@ -655,6 +639,12 @@ static BOOL debugSoParts = NO; NSData *data; key = [[_fetchKeys objectAtIndex:i] objectForKey: @"key"]; + + // We'll ask for the body.peek[] but SOPE returns us body[] responses + // so the key won't ever be found. + if ([key hasPrefix: @"body.peek["]) + key = [NSString stringWithFormat: @"body[%@", [key substringFromIndex: 10]]; + data = [(NSDictionary *)[(NSDictionary *)result objectForKey:key] objectForKey: @"data"]; @@ -1345,11 +1335,6 @@ static BOOL debugSoParts = NO; return mailETag; } -- (int) zlGenerationCount -{ - return 0; /* mails never change */ -} - - (NSArray *) aclsForUser: (NSString *) uid { return [container aclsForUser: uid]; @@ -1533,7 +1518,7 @@ static BOOL debugSoParts = NO; NSRange range; rc = nil; - fetch = [self _fetchProperty: @"BODY[HEADER.FIELDS (RECEIVED)]"]; + fetch = [self _fetchProperty: @"BODY.PEEK[HEADER.FIELDS (RECEIVED)]"]; if ([fetch count]) { @@ -1568,7 +1553,7 @@ static BOOL debugSoParts = NO; NSString *value, *rc; rc = nil; - fetch = [self _fetchProperty: @"BODY[HEADER.FIELDS (REFERENCES)]"]; + fetch = [self _fetchProperty: @"BODY.PEEK[HEADER.FIELDS (REFERENCES)]"]; if ([fetch count]) { diff --git a/UI/Common/Hungarian.lproj/Localizable.strings b/UI/Common/Hungarian.lproj/Localizable.strings index 2d2940263..e7cad04e0 100644 --- a/UI/Common/Hungarian.lproj/Localizable.strings +++ b/UI/Common/Hungarian.lproj/Localizable.strings @@ -69,6 +69,7 @@ "You cannot create a list in a shared address book." = "Nem hozható létre lista egy megosztott címjegyzékben."; "Warning" = "Figyelmeztetés"; +"Can't contact server" = "Hiba történt a kiszolgálóhoz kapcsolódás során. Kérem próbálja újra később."; "You are not allowed to access this module or this system. Please contact your system administrator." = "Önnek nem engedélyezett a hozzáférés ehhez a modulhoz vagy rendszerhez. Kérem lépjen kapcsolatba a rendszergazdával."; @@ -101,6 +102,7 @@ "Due Date:" = "Lejárat dátuma:"; "Location:" = "Hely:"; +/* mail labels */ /* Mail labels */ "Important" = "Fontos"; "Work" = "Hivatalos"; diff --git a/UI/Contacts/UIxContactEditor.m b/UI/Contacts/UIxContactEditor.m index 8179c51d2..82ad1941e 100644 --- a/UI/Contacts/UIxContactEditor.m +++ b/UI/Contacts/UIxContactEditor.m @@ -219,17 +219,7 @@ static Class SOGoContactGCSEntryK = Nil; - (NSString *) addressBookDisplayName { - NSString *fDisplayName; - SOGoObject *folder; - SOGoContactFolders *parentFolder; - - fDisplayName = [addressBookItem displayName]; - folder = [[self clientObject] container]; - parentFolder = [folder container]; - if ([fDisplayName isEqualToString: [parentFolder defaultFolderName]]) - fDisplayName = [self labelForKey: fDisplayName]; - - return fDisplayName; + return [addressBookItem displayName]; } - (BOOL) supportCategories diff --git a/UI/MailerUI/Dutch.lproj/Localizable.strings b/UI/MailerUI/Dutch.lproj/Localizable.strings index 75493fac3..6acbcf775 100644 --- a/UI/MailerUI/Dutch.lproj/Localizable.strings +++ b/UI/MailerUI/Dutch.lproj/Localizable.strings @@ -28,7 +28,7 @@ "Select a recipient from an Address Book" = "Kies een ontvanger uit een adresboek"; "Include an attachment" = "Voeg een bijlage toe"; "Save this message" = "Sla dit bericht op"; -"Get new messages" = "Haal nieuwe berichten"; +"Get new messages" = "Haal nieuwe berichten op"; "Create a new message" = "Maak een nieuw bericht"; "Go to address book" = "Ga naar adresboek"; "Reply to the message" = "Beantwoord het bericht"; @@ -97,11 +97,12 @@ "Reply-To" = "Reply-To"; "Add address" = "Adres toevoegen"; -"Attachments:" = "Bijlage:"; "Open" = "Openen"; "Select All" = "Selecteer Alles"; "Attach Web Page..." = "Voeg Webpagina toe..."; -"Attach File(s)..." = "Voeg Bestand(en) toe..."; +"file" = "bestand"; +"files" = "bestanden"; +"Save all" = "Alles opslaan"; "to" = "Aan"; "cc" = "Cc"; @@ -278,6 +279,9 @@ "error_missingsubject" = "U heeft geen onderwerp opgegeven!"; "error_missingrecipients" = "U heeft geen ontvanger opgegeven!"; "Send Anyway" = "Toch verzenden"; +"Error while saving the draft:" = "Fout bij het opslaan van het concept:"; +"Error while uploading the file \"%{0}\":" = "Fout bij het uploaden van het bestand \"%{0}\":"; +"There is an active file upload. Closing the window will interrupt it." = "Een bestandsupload is actief. Sluiten van het venster zal hem onderbreken."; /* Message sending */ "cannot send message: (smtp) all recipients discarded" = "Kan bericht niet sturen: alle ontvangers zijn ongeldig."; diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m index 8cf025796..d95e6fd34 100644 --- a/UI/PreferencesUI/UIxPreferences.m +++ b/UI/PreferencesUI/UIxPreferences.m @@ -551,7 +551,7 @@ static NSArray *reminderValues = nil; - (void) setReminder: (NSString *) theReminder { NSString *value; - int index; + NSUInteger index; index = NSNotFound; value = @"NONE"; diff --git a/UI/Scheduler/SpanishArgentina.lproj/Localizable.strings b/UI/Scheduler/SpanishArgentina.lproj/Localizable.strings index ad0080835..dc5390d14 100644 --- a/UI/Scheduler/SpanishArgentina.lproj/Localizable.strings +++ b/UI/Scheduler/SpanishArgentina.lproj/Localizable.strings @@ -58,7 +58,7 @@ "Export Calendar..." = "Exportar calendario..."; "Import Events..." = "Importar Eventos..."; "Import Events" = "Importar Eventos"; -"Select an iCalendar file (.ics)." = "Seleccionar un fichero iCalendar (.ics)."; +"Select an iCalendar file (.ics)." = "Seleccionar un archivo iCalendar (.ics)."; "Upload" = "Subir"; "Uploading" = "Cargando"; "Publish Calendar..." = "Publicar calendario..."; @@ -179,6 +179,8 @@ "Reminder:" = "Recordatorio:"; "General:" = "General:"; "Reply:" = "Responder:"; +"Created by:" = "Creado por:"; + "Target:" = "URL documento:"; @@ -373,6 +375,9 @@ "Show Time as Free" = "Mostrar tiempo como disponible"; +/* email notifications */ +"Send Appointment Notifications" = "Enviar notificaciones sobre el evento"; + /* validation errors */ validate_notitle = "No ha escrito un título, ¿Desea continuar?"; @@ -418,7 +423,7 @@ validate_endbeforestart = "La fecha/hora de inicio es posterior a la de fin." "You cannot remove nor unsubscribe from your personal calendar." = "No puede quitarse ni darse de baja de su calendario personal."; "Are you sure you want to delete the calendar \"%{0}\"?" -= "¿Está seguro/a que desea borrar el calendario \"%{0}\"?"; += "¿Está seguro de que quiere borrar el calendario \"%{0}\"?"; /* Legend */ "Participant" = "Asistente"; @@ -449,7 +454,7 @@ validate_endbeforestart = "La fecha/hora de inicio es posterior a la de fin." "and" = "y"; "A time conflict exists with one or more attendees.\nWould you like to keep the current settings anyway?" -= "Existe un conflicto de disponibilidad con uno o más asistentes.\n¿Quiere guardar ésta propuesta de todas formas?"; += "Existe un conflicto de disponibilidad entre uno o más asistentes.\n¿Quiere guardar ésta propuesta de todas formas?"; /* apt list */ "Title" = "Título"; @@ -484,7 +489,7 @@ vtodo_class2 = "(Tarea confidencial)"; "Name:" = "Nombre:"; "Color:" = "Color:"; -"Include in free-busy" = "Incluye en tiempo libre-ocupado"; +"Include in free-busy" = "Incluir en información de disponibilidad"; "Synchronization" = "Sincronización"; "Synchronize" = "Sincronizar"; @@ -506,12 +511,12 @@ vtodo_class2 = "(Tarea confidencial)"; "WebDAV XML URL" = "URL XML WebDAV"; /* Error messages */ -"dayFieldInvalid" = "Por favor, especificar un valor numérico en el campo día superior o igual a 1."; -"weekFieldInvalid" = "Por favor, especificar un valor numérico en el campo semana(s) superior o igual a 1."; -"monthFieldInvalid" = "Por favor, especificar un valor numérico en el campo mes superior o igual a 1."; -"monthDayFieldInvalid" = "Por favor, especificar un valor numérico en el campo día del mes superior o igual a 1."; -"yearFieldInvalid" = "Por favor, especificar un valor numérico en el campo año superior o igual a 1."; -"appointmentFieldInvalid" = "Por favor, especificar un valor numérico en el campo cita(s) superior o igual a 1."; +"dayFieldInvalid" = "Por favor, especificar un valor numérico en el campo día mayor o igual a 1."; +"weekFieldInvalid" = "Por favor, especificar un valor numérico en el campo semana(s) mayor o igual a 1."; +"monthFieldInvalid" = "Por favor, especificar un valor numérico en el campo mes mayor o igual a 1."; +"monthDayFieldInvalid" = "Por favor, especificar un valor numérico en el campo día del mes mayor o igual a 1."; +"yearFieldInvalid" = "Por favor, especificar un valor numérico en el campo año mayor o igual a 1."; +"appointmentFieldInvalid" = "Por favor, especificar un valor numérico en el campo cita(s) mayor o igual a 1."; "recurrenceUnsupported" = "Este tipo de frecuencia no esta soportado."; "Please specify a calendar name." = "Por favor ingrese el nombre del calendario."; "tagNotDefined" = "Tiene que especificar una etiqueta si quiere sincronizar este calendario."; diff --git a/UI/WebServerResources/ContactsUI.js b/UI/WebServerResources/ContactsUI.js index d9ad90077..fda104bb0 100644 --- a/UI/WebServerResources/ContactsUI.js +++ b/UI/WebServerResources/ContactsUI.js @@ -76,14 +76,32 @@ function contactsListCallback(http) { row.setAttribute("categories", contact["c_categories"]); row.setAttribute("contactname", contact["c_cn"]); var cells = row.getElementsByTagName("TD"); - $(cells[0]).update(contact["c_cn"].escapeHTML()); + if (contact["c_cn"]) + $(cells[0]).update(contact["c_cn"].escapeHTML()); + else + $(cells[0]).update(); cells[0].title = contact["c_cn"]; - $(cells[1]).update(contact["c_mail"].escapeHTML()); + log('mail ' + contact["c_mail"]); + if (contact["c_mail"]) + $(cells[1]).update(contact["c_mail"].escapeHTML()); + else + $(cells[1]).update(); cells[1].title = contact["c_mail"]; if (fullView) { - $(cells[2]).update(contact["c_screenname"].escapeHTML()); - $(cells[3]).update(contact["c_o"].escapeHTML()); - $(cells[4]).update(contact["c_telephonenumber"].escapeHTML()); + if (contact["c_screenname"]) + $(cells[2]).update(contact["c_screenname"].escapeHTML()); + else + $(cells[2]).update(); + + if (contact["c_o"]) + $(cells[3]).update(contact["c_o"].escapeHTML()); + else + $(cells[3]).update(); + + if (contact["c_telephonenumber"]) + $(cells[4]).update(contact["c_telephonenumber"].escapeHTML()); + else + $(cells[4]).update(); } } @@ -103,13 +121,17 @@ function contactsListCallback(http) { null, null, row); - cell.update(contact["c_cn"].escapeHTML()); - cell.title = contact["c_cn"]; + + if (contact["c_cn"]) { + $(cell).update(contact["c_cn"].escapeHTML()); + cell.title = contact["c_cn"]; + } cell = document.createElement("td"); row.appendChild(cell); + if (contact["c_mail"]) { - cell.update(contact["c_mail"].escapeHTML()); + $(cell).update(contact["c_mail"].escapeHTML()); cell.title = contact["c_mail"]; } @@ -117,17 +139,17 @@ function contactsListCallback(http) { cell = document.createElement("td"); row.appendChild(cell); if (contact["c_screenname"]) - cell.update(contact["c_screenname"].escapeHTML()); + $(cell).update(contact["c_screenname"].escapeHTML()); cell = document.createElement("td"); row.appendChild(cell); if (contact["c_o"]) - cell.update(contact["c_o"].escapeHTML()); + $(cell).update(contact["c_o"].escapeHTML()); cell = document.createElement("td"); row.appendChild(cell); if (contact["c_telephonenumber"]) - cell.update(contact["c_telephonenumber"].escapeHTML()); + $(cell).update(contact["c_telephonenumber"].escapeHTML()); } } } @@ -136,7 +158,7 @@ function contactsListCallback(http) { for (i = rows.length - 1; i >= data.length; i--) { tbody.removeChild(rows[i]); } - + if (sorting["attribute"] && sorting["attribute"].length > 0) { var sortHeader; if (sorting["attribute"] == "c_cn") diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index 8348dfd8c..18d45e1e7 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -245,7 +245,7 @@ function mailListToggleMessageThread(row, cell) { /* Triggered when clicking on the read/unread dot of a message row or * through the contextual menu. */ -function mailListToggleMessagesRead(row) { +function mailListToggleMessagesRead(row, force_mark_as_read) { var selectedRowsId = []; if (row) { selectedRowsId = [row.id]; @@ -265,10 +265,13 @@ function mailListToggleMessagesRead(row) { action = 'markMessageRead'; markread = true; } - else { + else if (!force_mark_as_read) { action = 'markMessageUnread'; markread = false; } + else { + return; + } for (var i = 0; i < selectedRowsId.length; i++) { var msguid = selectedRowsId[i].split('_')[1]; @@ -1224,8 +1227,6 @@ function loadMessage(msguid) { { 'mailbox': Mailer.currentMailbox, 'msguid': msguid, 'seenStateHasChanged': seenStateHasChanged }); - // Warning: We assume the user can set the read/unread flag of the message. - markMailInWindow(window, msguid, true); } else { div.innerHTML = cachedMessage['text']; @@ -1643,6 +1644,9 @@ function loadMessageCallback(http) { cachedMessage['text'] = http.responseText; if (cachedMessage['text'].length < 30000) storeCachedMessage(cachedMessage); + + // We mark the mail as read + mailListToggleMessagesRead($("row_" + msguid), true); } } else if (http.status == 404) { diff --git a/UI/WebServerResources/UIxFilterEditor.js b/UI/WebServerResources/UIxFilterEditor.js index 3d38c5da1..5aee2f201 100644 --- a/UI/WebServerResources/UIxFilterEditor.js +++ b/UI/WebServerResources/UIxFilterEditor.js @@ -516,7 +516,7 @@ function ensureMethodSelectRepresentation(container, methodSpan) { if (sieveCapabilities.indexOf("fileinto") > -1) { methods.push("fileinto"); } - if (sieveCapabilities.indexOf("imapflags") > -1) { + if (sieveCapabilities.indexOf("imapflags") > -1 || sieveCapabilities.indexOf("imap4flags") > -1) { methods.push("addflag"); } methods.push("stop"); diff --git a/UI/WebServerResources/ckeditor/build-config.js b/UI/WebServerResources/ckeditor/build-config.js index 1366445fd..b5a99778e 100644 --- a/UI/WebServerResources/ckeditor/build-config.js +++ b/UI/WebServerResources/ckeditor/build-config.js @@ -13,10 +13,10 @@ * (1) http://ckeditor.com/builder * Visit online builder to build CKEditor from scratch. * - * (2) http://ckeditor.com/builder/740a5c2b5fb85f37a81edd89153c2c81 + * (2) http://ckeditor.com/builder/7df2f18471fb3861d98e6e0960792954 * Visit online builder to build CKEditor, starting with the same setup as before. * - * (3) http://ckeditor.com/builder/download/740a5c2b5fb85f37a81edd89153c2c81 + * (3) http://ckeditor.com/builder/download/7df2f18471fb3861d98e6e0960792954 * Straight download link to the latest version of CKEditor (Optimized) with the same setup as before. * * NOTE: diff --git a/UI/WebServerResources/ckeditor/ckeditor.js b/UI/WebServerResources/ckeditor/ckeditor.js index 053703bb3..625410478 100644 --- a/UI/WebServerResources/ckeditor/ckeditor.js +++ b/UI/WebServerResources/ckeditor/ckeditor.js @@ -2,40 +2,40 @@ Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ -(function(){if(window.CKEDITOR&&window.CKEDITOR.dom)return;window.CKEDITOR||(window.CKEDITOR=function(){var a={timestamp:"E1PE",version:"4.3.3",revision:"7841b02",rnd:Math.floor(900*Math.random())+100,_:{pending:[]},status:"unloaded",basePath:function(){var b=window.CKEDITOR_BASEPATH||"";if(!b)for(var e=document.getElementsByTagName("script"),a=0;a=0;r--)if(n[r].priority<=m){n.splice(r+1,0,j);return{removeListener:i}}n.unshift(j)}return{removeListener:i}}, -once:function(){var b=arguments[1];arguments[1]=function(e){e.removeListener();return b.apply(this,arguments)};return this.on.apply(this,arguments)},capture:function(){CKEDITOR.event.useCapture=1;var b=this.on.apply(this,arguments);CKEDITOR.event.useCapture=0;return b},fire:function(){var b=0,e=function(){b=1},a=0,h=function(){a=1};return function(m,j,i){var n=d(this)[m],m=b,s=a;b=a=0;if(n){var r=n.listeners;if(r.length)for(var r=r.slice(0),v,f=0;f=0&&a.listeners.splice(h,1)}},removeAllListeners:function(){var b=d(this),e;for(e in b)delete b[e]},hasListeners:function(b){return(b=d(this)[b])&&b.listeners.length>0}}}()); +return{define:function(b,e){var i=a.call(this,b);CKEDITOR.tools.extend(i,e,true)},on:function(b,e,i,d,l){function h(a,f,o,s){a={name:b,sender:this,editor:a,data:f,listenerData:d,stop:o,cancel:s,removeListener:k};return e.call(i,a)===false?false:a.data}function k(){s.removeListener(b,e)}var o=a.call(this,b);if(o.getListenerIndex(e)<0){o=o.listeners;i||(i=this);isNaN(l)&&(l=10);var s=this;h.fn=e;h.priority=l;for(var q=o.length-1;q>=0;q--)if(o[q].priority<=l){o.splice(q+1,0,h);return{removeListener:k}}o.unshift(h)}return{removeListener:k}}, +once:function(){var b=arguments[1];arguments[1]=function(e){e.removeListener();return b.apply(this,arguments)};return this.on.apply(this,arguments)},capture:function(){CKEDITOR.event.useCapture=1;var b=this.on.apply(this,arguments);CKEDITOR.event.useCapture=0;return b},fire:function(){var b=0,e=function(){b=1},a=0,g=function(){a=1};return function(l,h,k){var o=d(this)[l],l=b,s=a;b=a=0;if(o){var q=o.listeners;if(q.length)for(var q=q.slice(0),u,f=0;f=0&&a.listeners.splice(g,1)}},removeAllListeners:function(){var b=d(this),e;for(e in b)delete b[e]},hasListeners:function(b){return(b=d(this)[b])&&b.listeners.length>0}}}()); CKEDITOR.editor||(CKEDITOR.editor=function(){CKEDITOR._.pending.push([this,arguments]);CKEDITOR.event.call(this)},CKEDITOR.editor.prototype.fire=function(a,d){a in{instanceReady:1,loaded:1}&&(this[a]=true);return CKEDITOR.event.prototype.fire.call(this,a,d,this)},CKEDITOR.editor.prototype.fireOnce=function(a,d){a in{instanceReady:1,loaded:1}&&(this[a]=true);return CKEDITOR.event.prototype.fireOnce.call(this,a,d,this)},CKEDITOR.event.implementOn(CKEDITOR.editor.prototype)); -CKEDITOR.env||(CKEDITOR.env=function(){var a=navigator.userAgent.toLowerCase(),d=window.opera,b={ie:a.indexOf("trident/")>-1,opera:!!d&&d.version,webkit:a.indexOf(" applewebkit/")>-1,air:a.indexOf(" adobeair/")>-1,mac:a.indexOf("macintosh")>-1,quirks:document.compatMode=="BackCompat"&&(!document.documentMode||document.documentMode<10),mobile:a.indexOf("mobile")>-1,iOS:/(ipad|iphone|ipod)/.test(a),isCustomDomain:function(){if(!this.ie)return false;var e=document.domain,b=window.location.hostname;return e!= -b&&e!="["+b+"]"},secure:location.protocol=="https:"};b.gecko=navigator.product=="Gecko"&&!b.webkit&&!b.opera&&!b.ie;if(b.webkit)a.indexOf("chrome")>-1?b.chrome=true:b.safari=true;var c=0;if(b.ie){c=b.quirks||!document.documentMode?parseFloat(a.match(/msie (\d+)/)[1]):document.documentMode;b.ie9Compat=c==9;b.ie8Compat=c==8;b.ie7Compat=c==7;b.ie6Compat=c<7||b.quirks}if(b.gecko){var e=a.match(/rv:([\d\.]+)/);if(e){e=e[1].split(".");c=e[0]*1E4+(e[1]||0)*100+(e[2]||0)*1}}b.opera&&(c=parseFloat(d.version())); +CKEDITOR.env||(CKEDITOR.env=function(){var a=navigator.userAgent.toLowerCase(),d=window.opera,b={ie:a.indexOf("trident/")>-1,opera:!!d&&d.version,webkit:a.indexOf(" applewebkit/")>-1,air:a.indexOf(" adobeair/")>-1,mac:a.indexOf("macintosh")>-1,quirks:document.compatMode=="BackCompat"&&(!document.documentMode||document.documentMode<10),mobile:a.indexOf("mobile")>-1,iOS:/(ipad|iphone|ipod)/.test(a),isCustomDomain:function(){if(!this.ie)return false;var b=document.domain,e=window.location.hostname;return b!= +e&&b!="["+e+"]"},secure:location.protocol=="https:"};b.gecko=navigator.product=="Gecko"&&!b.webkit&&!b.opera&&!b.ie;if(b.webkit)a.indexOf("chrome")>-1?b.chrome=true:b.safari=true;var c=0;if(b.ie){c=b.quirks||!document.documentMode?parseFloat(a.match(/msie (\d+)/)[1]):document.documentMode;b.ie9Compat=c==9;b.ie8Compat=c==8;b.ie7Compat=c==7;b.ie6Compat=c<7||b.quirks}if(b.gecko){var e=a.match(/rv:([\d\.]+)/);if(e){e=e[1].split(".");c=e[0]*1E4+(e[1]||0)*100+(e[2]||0)*1}}b.opera&&(c=parseFloat(d.version())); b.air&&(c=parseFloat(a.match(/ adobeair\/(\d+)/)[1]));b.webkit&&(c=parseFloat(a.match(/ applewebkit\/(\d+)/)[1]));b.version=c;b.isCompatible=b.iOS&&c>=534||!b.mobile&&(b.ie&&c>6||b.gecko&&c>=10801||b.opera&&c>=9.5||b.air&&c>=1||b.webkit&&c>=522||false);b.hidpi=window.devicePixelRatio>=2;b.needsBrFiller=b.gecko||b.webkit||b.ie&&c>10;b.needsNbspFiller=b.ie&&c<11;b.cssClass="cke_browser_"+(b.ie?"ie":b.gecko?"gecko":b.opera?"opera":b.webkit?"webkit":"unknown");if(b.quirks)b.cssClass=b.cssClass+" cke_browser_quirks"; if(b.ie){b.cssClass=b.cssClass+(" cke_browser_ie"+(b.quirks||b.version<7?"6":b.version));if(b.quirks)b.cssClass=b.cssClass+" cke_browser_iequirks"}if(b.gecko)if(c<10900)b.cssClass=b.cssClass+" cke_browser_gecko18";else if(c<=11E3)b.cssClass=b.cssClass+" cke_browser_gecko19";if(b.air)b.cssClass=b.cssClass+" cke_browser_air";if(b.iOS)b.cssClass=b.cssClass+" cke_browser_ios";if(b.hidpi)b.cssClass=b.cssClass+" cke_hidpi";return b}()); "unloaded"==CKEDITOR.status&&function(){CKEDITOR.event.implementOn(CKEDITOR);CKEDITOR.loadFullCore=function(){if(CKEDITOR.status!="basic_ready")CKEDITOR.loadFullCore._load=1;else{delete CKEDITOR.loadFullCore;var a=document.createElement("script");a.type="text/javascript";a.src=CKEDITOR.basePath+"ckeditor.js";document.getElementsByTagName("head")[0].appendChild(a)}};CKEDITOR.loadFullCoreTimeout=0;CKEDITOR.add=function(a){(this._.pending||(this._.pending=[])).push(a)};(function(){CKEDITOR.domReady(function(){var a= CKEDITOR.loadFullCore,d=CKEDITOR.loadFullCoreTimeout;if(a){CKEDITOR.status="basic_ready";a&&a._load?a():d&&setTimeout(function(){CKEDITOR.loadFullCore&&CKEDITOR.loadFullCore()},d*1E3)}})})();CKEDITOR.status="basic_loaded"}();CKEDITOR.dom={}; (function(){var a=[],d=CKEDITOR.env.gecko?"-moz-":CKEDITOR.env.webkit?"-webkit-":CKEDITOR.env.opera?"-o-":CKEDITOR.env.ie?"-ms-":"";CKEDITOR.on("reset",function(){a=[]});CKEDITOR.tools={arrayCompare:function(b,a){if(!b&&!a)return true;if(!b||!a||b.length!=a.length)return false;for(var e=0;e"+a+""):e.push('');return e.join("")},htmlEncode:function(b){return(""+b).replace(/&/g,"&").replace(/>/g,">").replace(//g,">")},htmlDecodeAttr:function(b){return b.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">")},getNextNumber:function(){var b=0;return function(){return++b}}(),getNextId:function(){return"cke_"+this.getNextNumber()},override:function(b,a){var e=a(b);e.prototype=b.prototype;return e},setTimeout:function(b,a,e,g,d){d||(d=window);e||(e=d);return d.setTimeout(function(){g?b.apply(e,[].concat(g)): -b.apply(e)},a||0)},trim:function(){var b=/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;return function(a){return a.replace(b,"")}}(),ltrim:function(){var b=/^[ \t\n\r]+/g;return function(a){return a.replace(b,"")}}(),rtrim:function(){var b=/[ \t\n\r]+$/g;return function(a){return a.replace(b,"")}}(),indexOf:function(b,a){if(typeof a=="function")for(var e=0,g=b.length;e=0?b[e]:null},bind:function(b,a){return function(){return b.apply(a,arguments)}},createClass:function(b){var a=b.$,e=b.base,g=b.privates||b._,d=b.proto,b=b.statics;!a&&(a=function(){e&&this.base.apply(this,arguments)});if(g)var m=a,a=function(){var e=this._||(this._={}),a;for(a in g){var b=g[a];e[a]=typeof b=="function"?CKEDITOR.tools.bind(b,this):b}m.apply(this,arguments)};if(e){a.prototype=this.prototypedCopy(e.prototype);a.prototype.constructor=a;a.base= +b instanceof String||b instanceof Number||b instanceof Boolean||b instanceof Date||b instanceof RegExp)return b;a=new b.constructor;for(e in b)a[e]=CKEDITOR.tools.clone(b[e]);return a},capitalize:function(b,a){return b.charAt(0).toUpperCase()+(a?b.slice(1):b.slice(1).toLowerCase())},extend:function(b){var a=arguments.length,e,i;if(typeof(e=arguments[a-1])=="boolean")a--;else if(typeof(e=arguments[a-2])=="boolean"){i=arguments[a-1];a=a-2}for(var d=1;d"+a+""):e.push('');return e.join("")},htmlEncode:function(b){return(""+b).replace(/&/g,"&").replace(/>/g,">").replace(//g,">")},htmlDecodeAttr:function(b){return b.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">")},getNextNumber:function(){var b=0;return function(){return++b}}(),getNextId:function(){return"cke_"+this.getNextNumber()},override:function(b,a){var e=a(b);e.prototype=b.prototype;return e},setTimeout:function(b,a,e,i,d){d||(d=window);e||(e=d);return d.setTimeout(function(){i?b.apply(e,[].concat(i)): +b.apply(e)},a||0)},trim:function(){var b=/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;return function(a){return a.replace(b,"")}}(),ltrim:function(){var b=/^[ \t\n\r]+/g;return function(a){return a.replace(b,"")}}(),rtrim:function(){var b=/[ \t\n\r]+$/g;return function(a){return a.replace(b,"")}}(),indexOf:function(b,a){if(typeof a=="function")for(var e=0,i=b.length;e=0?b[e]:null},bind:function(b,a){return function(){return b.apply(a,arguments)}},createClass:function(b){var a=b.$,e=b.base,i=b.privates||b._,d=b.proto,b=b.statics;!a&&(a=function(){e&&this.base.apply(this,arguments)});if(i)var l=a,a=function(){var a=this._||(this._={}),b;for(b in i){var e=i[b];a[b]=typeof e=="function"?CKEDITOR.tools.bind(e,this):e}l.apply(this,arguments)};if(e){a.prototype=this.prototypedCopy(e.prototype);a.prototype.constructor=a;a.base= e;a.baseProto=e.prototype;a.prototype.base=function(){this.base=e.prototype.base;e.apply(this,arguments);this.base=arguments.callee}}d&&this.extend(a.prototype,d,true);b&&this.extend(a,b,true);return a},addFunction:function(b,c){return a.push(function(){return b.apply(c||this,arguments)})-1},removeFunction:function(b){a[b]=null},callFunction:function(b){var c=a[b];return c&&c.apply(window,Array.prototype.slice.call(arguments,1))},cssLength:function(){var a=/^-?\d+\.?\d*px$/,c;return function(e){c= -CKEDITOR.tools.trim(e+"")+"px";return a.test(c)?c:e||""}}(),convertToPx:function(){var a;return function(c){if(!a){a=CKEDITOR.dom.element.createFromHtml('
',CKEDITOR.document);CKEDITOR.document.getBody().append(a)}if(!/%$/.test(c)){a.setStyle("width",c);return a.$.clientWidth}return c}}(),repeat:function(a,c){return Array(c+1).join(a)},tryThese:function(){for(var a,c=0,e=arguments.length;c',CKEDITOR.document);CKEDITOR.document.getBody().append(a)}if(!/%$/.test(c)){a.setStyle("width",c);return a.$.clientWidth}return c}}(),repeat:function(a,c){return Array(c+1).join(a)},tryThese:function(){for(var a,c=0,e=arguments.length;c8)&&d)a=d+":"+a;return new CKEDITOR.dom.nodeList(this.$.getElementsByTagName(a))},getHead:function(){var a=this.$.getElementsByTagName("head")[0];return a= +0;b&&c8)&&d)a=d+":"+a;return new CKEDITOR.dom.nodeList(this.$.getElementsByTagName(a))},getHead:function(){var a=this.$.getElementsByTagName("head")[0];return a= a?new CKEDITOR.dom.element(a):this.getDocumentElement().append(new CKEDITOR.dom.element("head"),true)},getBody:function(){return new CKEDITOR.dom.element(this.$.body)},getDocumentElement:function(){return new CKEDITOR.dom.element(this.$.documentElement)},getWindow:function(){return new CKEDITOR.dom.window(this.$.parentWindow||this.$.defaultView)},write:function(a){this.$.open("text/html","replace");CKEDITOR.env.ie&&(a=a.replace(/(?:^\s*]*?>)|^/i,'$&\n