Merge pull request #146 from Zentyal/merge-from-upstream

Merge from upstream
This commit is contained in:
Julio J. García Martín 2015-06-04 18:53:24 +02:00
commit c0a22ead1d
152 changed files with 6559 additions and 625 deletions

View file

@ -12,6 +12,7 @@ trans.da_DK = UI/MailerUI/Danish.lproj/Localizable.strings
trans.de = UI/MailerUI/German.lproj/Localizable.strings
trans.es_AR = UI/MailerUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MailerUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MailerUI/Basque.lproj/Localizable.strings
trans.fi = UI/MailerUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MailerUI/French.lproj/Localizable.strings
trans.hu = UI/MailerUI/Hungarian.lproj/Localizable.strings
@ -38,6 +39,7 @@ trans.da_DK = UI/PreferencesUI/Danish.lproj/Localizable.strings
trans.de = UI/PreferencesUI/German.lproj/Localizable.strings
trans.es_AR = UI/PreferencesUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/PreferencesUI/Basque.lproj/Localizable.strings
trans.fi = UI/PreferencesUI/Finnish.lproj/Localizable.strings
trans.fr = UI/PreferencesUI/French.lproj/Localizable.strings
trans.hu = UI/PreferencesUI/Hungarian.lproj/Localizable.strings
@ -64,6 +66,7 @@ trans.da_DK = UI/Scheduler/Danish.lproj/Localizable.strings
trans.de = UI/Scheduler/German.lproj/Localizable.strings
trans.es_AR = UI/Scheduler/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Scheduler/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Scheduler/Basque.lproj/Localizable.strings
trans.fi = UI/Scheduler/Finnish.lproj/Localizable.strings
trans.fr = UI/Scheduler/French.lproj/Localizable.strings
trans.hu = UI/Scheduler/Hungarian.lproj/Localizable.strings
@ -90,6 +93,7 @@ trans.da_DK = UI/Contacts/Danish.lproj/Localizable.strings
trans.de = UI/Contacts/German.lproj/Localizable.strings
trans.es_AR = UI/Contacts/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Contacts/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Contacts/Basque.lproj/Localizable.strings
trans.fi = UI/Contacts/Finnish.lproj/Localizable.strings
trans.fr = UI/Contacts/French.lproj/Localizable.strings
trans.hu = UI/Contacts/Hungarian.lproj/Localizable.strings
@ -116,6 +120,7 @@ trans.da_DK = UI/MainUI/Danish.lproj/Localizable.strings
trans.de = UI/MainUI/German.lproj/Localizable.strings
trans.es_AR = UI/MainUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MainUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MainUI/Basque.lproj/Localizable.strings
trans.fi = UI/MainUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MainUI/French.lproj/Localizable.strings
trans.hu = UI/MainUI/Hungarian.lproj/Localizable.strings
@ -142,6 +147,7 @@ trans.da_DK = UI/Common/Danish.lproj/Localizable.strings
trans.de = UI/Common/German.lproj/Localizable.strings
trans.es_AR = UI/Common/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Common/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Common/Basque.lproj/Localizable.strings
trans.fi = UI/Common/Finnish.lproj/Localizable.strings
trans.fr = UI/Common/French.lproj/Localizable.strings
trans.hu = UI/Common/Hungarian.lproj/Localizable.strings
@ -168,6 +174,7 @@ trans.da_DK = UI/AdministrationUI/Danish.lproj/Localizable.strings
trans.de = UI/AdministrationUI/German.lproj/Localizable.strings
trans.es_AR = UI/AdministrationUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/AdministrationUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/AdministrationUI/Basque.lproj/Localizable.strings
trans.fi = UI/AdministrationUI/Finnish.lproj/Localizable.strings
trans.fr = UI/AdministrationUI/French.lproj/Localizable.strings
trans.hu = UI/AdministrationUI/Hungarian.lproj/Localizable.strings
@ -194,6 +201,7 @@ trans.da_DK = SoObjects/Appointments/Danish.lproj/Localizable.strings
trans.de = SoObjects/Appointments/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Appointments/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Appointments/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Appointments/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Appointments/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Appointments/French.lproj/Localizable.strings
trans.hu = SoObjects/Appointments/Hungarian.lproj/Localizable.strings
@ -220,6 +228,7 @@ trans.da_DK = SoObjects/Contacts/Danish.lproj/Localizable.strings
trans.de = SoObjects/Contacts/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Contacts/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Contacts/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Contacts/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Contacts/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Contacts/French.lproj/Localizable.strings
trans.hu = SoObjects/Contacts/Hungarian.lproj/Localizable.strings
@ -246,6 +255,7 @@ trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Mailer/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
@ -272,6 +282,7 @@ trans.da_DK = UI/MailPartViewers/Danish.lproj/Localizable.strings
trans.de = UI/MailPartViewers/German.lproj/Localizable.strings
trans.es_AR = UI/MailPartViewers/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MailPartViewers/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MailPartViewers/Basque.lproj/Localizable.strings
trans.fi = UI/MailPartViewers/Finnish.lproj/Localizable.strings
trans.fr = UI/MailPartViewers/French.lproj/Localizable.strings
trans.hu = UI/MailPartViewers/Hungarian.lproj/Localizable.strings

View file

@ -32,6 +32,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSString.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSObject+Logs.h>
@ -45,11 +47,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) _dumpToFile
{
NSString *path;
BOOL debugOn;
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
[self errorWithFormat: @"Original data written to: %@", path];
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
if (debugOn)
{
NSString *path;
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
[self errorWithFormat: @"Original data written to: %@", path];
}
}
//

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2014, Inverse inc.
Copyright (c) 2014-2015, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -51,6 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) command;
- (NSString *) collectionid;
- (NSString *) itemid;
- (BOOL) acceptsMultiPart;
- (NSData *) convertHexStringToBytes;
@end

View file

@ -322,6 +322,18 @@ static NSArray *easCommandParameters = nil;
return s;
}
- (BOOL) acceptsMultiPart
{
NSString *s;
s = [self _valueForParameter: @"OPTIONS="];
if (s && [s rangeOfString: @"AcceptMultiPart" options: NSCaseInsensitiveSearch].location != NSNotFound)
return YES;
return NO;
}
//
// FIXME: combine with our OpenChange code.

View file

@ -131,6 +131,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] addEntriesFromDictionary: values];
@ -1068,14 +1069,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
changeDetected: (BOOL *) changeDetected
maxSyncResponseSize: (int) theMaxSyncResponseSize
{
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *lastServerKey, *syncKeyInCache;
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *mimeSupport, *lastServerKey, *syncKeyInCache;
SOGoMicrosoftActiveSyncFolderType folderType;
id collection, value;
NSMutableString *changeBuffer, *commandsBuffer;
BOOL getChanges, first_sync;
unsigned int windowSize, v, status;
NSMutableDictionary *folderMetadata;
NSMutableDictionary *folderMetadata, *folderOptions;
changeBuffer = [NSMutableString string];
commandsBuffer = [NSMutableString string];
@ -1124,20 +1125,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
first_sync = NO;
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]];
if ([syncKey isEqualToString: @"0"])
{
davCollectionTag = @"-1";
first_sync = YES;
*changeDetected = YES;
}
else if ((![syncKey isEqualToString: @"-1"]) && !([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"SyncCache"]))
else if ((![syncKey isEqualToString: @"-1"]) && !([folderMetadata objectForKey: @"SyncCache"]))
{
//NSLog(@"Reset folder: %@", [collection nameInContainer]);
davCollectionTag = @"0";
first_sync = YES;
*changeDetected = YES;
if (!([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"displayName"]))
if (!([folderMetadata objectForKey: @"displayName"]))
status = 12; // need folderSync
else
status = 3; // do a complete resync
@ -1147,7 +1150,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
bodyPreferenceType = [[(id)[[(id)[theDocumentElement getElementsByTagName: @"BodyPreference"] lastObject] getElementsByTagName: @"Type"] lastObject] textValue];
if (!bodyPreferenceType)
bodyPreferenceType = @"1";
{
bodyPreferenceType = [[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"BodyPreferenceType"];
// By default, send MIME mails. See #3146 for details.
if (!bodyPreferenceType)
bodyPreferenceType = @"4";
}
else
{
mimeSupport = [[(id)[theDocumentElement getElementsByTagName: @"MIMESupport"] lastObject] textValue];
if (!mimeSupport)
mimeSupport = [[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"MIMESupport"];
if (!mimeSupport)
mimeSupport = @"0";
if ([mimeSupport isEqualToString: @"1"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"2";
else if ([mimeSupport isEqualToString: @"2"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"4";
else if ([mimeSupport isEqualToString: @"0"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"2";
// Avoid writing to cache if there is nothing to change.
if (![[[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"BodyPreferenceType"] isEqualToString: bodyPreferenceType] ||
![[[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"MIMESupport"] isEqualToString: mimeSupport])
{
folderOptions = [[NSDictionary alloc] initWithObjectsAndKeys: mimeSupport, @"MIMESupport", bodyPreferenceType, @"BodyPreferenceType", nil];
[folderMetadata setObject: folderOptions forKey: @"FolderOptions"];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: collection withType: folderType]];
}
}
[context setObject: bodyPreferenceType forKey: @"BodyPreferenceType"];
@ -1416,6 +1452,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inBuffer: s
changeDetected: &changeDetected
maxSyncResponseSize: maxSyncResponseSize];
if (maxSyncResponseSize > 0 && [s length] >= maxSyncResponseSize)
break;
}
if (changeDetected)

View file

@ -61,6 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Connection.h>
@ -95,6 +96,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <SOGo/GCSSpecialQueries+SOGoCacheObject.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/WORequest+SOGo.h>
#import <SOGo/NSArray+Utilities.h>
#import <Appointments/SOGoAppointmentFolder.h>
#import <Appointments/SOGoAppointmentFolders.h>
@ -110,6 +112,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailFolder.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/SOGoMailObject+Draft.h>
#import <Mailer/NSString+Mail.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
@ -138,10 +143,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@implementation SOGoActiveSyncDispatcher
static BOOL debugOn = NO;
- (id) init
{
[super init];
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
folderTableURL = nil;
return self;
}
@ -917,6 +925,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[o save];
@ -1001,6 +1010,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
}
@ -1023,6 +1033,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
}
@ -1451,6 +1462,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
appointmentObject = [collection lookupName: [NSString stringWithFormat: @"%@.ics", [event uid]]
inContext: context
acquire: NO];
// Create the appointment if it is not added to calendar yet
if ([appointmentObject isKindOfClass: [NSException class]])
{
appointmentObject = [[SOGoAppointmentObject alloc] initWithName: [NSString stringWithFormat: @"%@.ics", [event uid]]
inContainer: collection];
[appointmentObject saveComponent: event];
}
}
}
@ -1486,7 +1505,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
else
{
[theResponse setStatus: 500];
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
[s appendString: @"<MeetingResponse xmlns=\"MeetingResponse:\">"];
[s appendString: @"<Result>"];
[s appendFormat: @"<RequestId>%@</RequestId>", requestId];
[s appendFormat: @"<Status>%d</Status>", 2];
[s appendString: @"</Result>"];
[s appendString: @"</MeetingResponse>"];
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
[theResponse setContent: d];
}
}
@ -1600,10 +1629,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// See http://msdn.microsoft.com/en-us/library/gg651088(v=exchg.80).aspx for Status response codes.
//
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
if ([prevSuccessfulMoveItemsOps objectForKey: srcMessageId])
{
// Previous move failed operation but we can recover the dstMessageId from previous request
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
[s appendFormat: @"<DstMsgId>%@</DstMsgId>", [prevSuccessfulMoveItemsOps objectForKey: srcMessageId]];
[s appendFormat: @"<Status>%d</Status>", 3];
[newSuccessfulMoveItemsOps setObject: [prevSuccessfulMoveItemsOps objectForKey: srcMessageId] forKey: srcMessageId];
@ -2088,13 +2117,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inResponse: (WOResponse *) theResponse
{
SOGoContactSourceFolder *currentFolder;
NSArray *allKeys, *allContacts, *mails;
NSDictionary *systemSources, *contact;
NSString *name, *query, *current_mail;
SOGoContactFolders *contactFolders;
NSArray *allKeys, *allContacts;
SOGoUserFolder *userFolder;
NSString *name, *query;
NSMutableString *s;
NSData *d;
id o;
int i, j, total;
@ -2145,18 +2175,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// We get the LDIF entry of our record, for easier processing
contact = [[currentFolder lookupName: [contact objectForKey: @"c_name"] inContext: context acquire: NO] ldifRecord];
[s appendString: @"<Result xmlns=\"Search:\">"];
[s appendString: @"<Properties>"];
[s appendFormat: @"<DisplayName xmlns=\"Gal:\">%@</DisplayName>", [contact objectForKey: @"displayname"]];
[s appendFormat: @"<FirstName xmlns=\"Gal:\">%@</FirstName>", [contact objectForKey: @"givenname"]];
[s appendFormat: @"<LastName xmlns=\"Gal:\">%@</LastName>", [contact objectForKey: @"sn"]];
[s appendFormat: @"<EmailAddress xmlns=\"Gal:\">%@</EmailAddress>", [contact objectForKey: @"mail"]];
[s appendFormat: @"<Phone xmlns=\"Gal:\">%@</Phone>", [contact objectForKey: @"telephonenumber"]];
[s appendFormat: @"<Company xmlns=\"Gal:\">%@</Company>", [contact objectForKey: @"o"]];
[s appendString: @"</Properties>"];
[s appendString: @"</Result>"];
total++;
o = [contact objectForKey: @"mail"];
if ([o isKindOfClass: [NSArray class]])
mails = o;
else
mails = [NSArray arrayWithObjects: o ? o : @"", nil];
for (total = 0; total < [mails count]; total++)
{
current_mail = [mails objectAtIndex: total];
[s appendString: @"<Result xmlns=\"Search:\">"];
[s appendString: @"<Properties>"];
if ((o = [contact objectForKey: @"displayname"]))
[s appendFormat: @"<DisplayName xmlns=\"Gal:\">%@</DisplayName>", o];
if ((o = [contact objectForKey: @"title"]))
[s appendFormat: @"<Title xmlns=\"Gal:\">%@</Title>", o];
if ((o = [contact objectForKey: @"givenname"]))
[s appendFormat: @"<FirstName xmlns=\"Gal:\">%@</FirstName>", o];
if ((o = [contact objectForKey: @"sn"]))
[s appendFormat: @"<LastName xmlns=\"Gal:\">%@</LastName>", o];
if ([current_mail length] > 0)
[s appendFormat: @"<EmailAddress xmlns=\"Gal:\">%@</EmailAddress>", current_mail];
if ((o = [contact objectForKey: @"telephonenumber"]))
[s appendFormat: @"<Phone xmlns=\"Gal:\">%@</Phone>", o];
if ((o = [contact objectForKey: @"homephone"]))
[s appendFormat: @"<HomePhone xmlns=\"Gal:\">%@</HomePhone>", o];
if ((o = [contact objectForKey: @"mobile"]))
[s appendFormat: @"<MobilePhone xmlns=\"Gal:\">%@</MobilePhone>", o];
if ((o = [contact objectForKey: @"o"]))
[s appendFormat: @"<Company xmlns=\"Gal:\">%@</Company>", o];
[s appendString: @"</Properties>"];
[s appendString: @"</Result>"];
}
}
}
@ -2332,26 +2394,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
//
// <?xml version="1.0"?>
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
// <SmartForward xmlns="ComposeMail:">
// <ClientId>C9FF94FE-EA40-473A-B3E2-AAEE94F753A4</ClientId>
// <SaveInSentItems/>
// <ReplaceMime/>
// <Source>
// <FolderId>mail/INBOX</FolderId>
// <ItemId>82</ItemId>
// </Source>
// <MIME>... the data ...</MIME>
// </SmartForward>
//
- (void) processSmartForward: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
- (void) _processSmartCommand: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
isSmartForward: (BOOL ) isSmartForward
{
NSString *folderId, *itemId, *realCollectionId;
SOGoMicrosoftActiveSyncFolderType folderType;
SOGoUserDefaults *ud;
BOOL htmlComposition, isHTML;
id value;
isHTML = NO;
ud = [[context activeUser] userDefaults];
folderId = [[(id)[theDocumentElement getElementsByTagName: @"FolderId"] lastObject] textValue];
@ -2400,11 +2455,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NGMutableHashMap *map;
NGMimeFileData *fdata;
NSException *error;
NSArray *attachmentKeys;
NSMutableArray *attachments;
id body, bodyFromSmartForward;
NSString *fullName, *email;
id body, bodyFromSmartForward, htmlPart, textPart;
NSString *fullName, *email, *charset, *s;
NSDictionary *identity;
int a;
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
@ -2415,7 +2474,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
mailObject = [currentCollection lookupName: itemId inContext: context acquire: NO];
parser = [[NGMimeMessageParser alloc] init];
data = [[[[(id)[theDocumentElement getElementsByTagName: @"MIME"] lastObject] textValue] stringByDecodingBase64] dataUsingEncoding: NSUTF8StringEncoding];
messageFromSmartForward = [parser parsePartFromData: data];
@ -2436,6 +2494,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
[map setObject: email forKey: @"from"];
if ([mailObject messageId])
[map setObject: [mailObject messageId] forKey: @"in-reply-to"];
messageToSend = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
body = [[[NGMimeMultipartBody alloc] initWithPart: messageToSend] autorelease];
@ -2443,12 +2504,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// we take the first part text/* part we see.
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
bodyFromSmartForward = nil;
textPart = nil;
htmlPart = nil;
attachments = [NSMutableArray array];
if ([[messageFromSmartForward body] isKindOfClass: [NGMimeMultipartBody class]])
{
NGMimeBodyPart *part;
NSArray *parts;
int i;
NGMimeBodyPart *part, *apart;
NSArray *parts, *aparts;
int i, j;
parts = [[messageFromSmartForward body] parts];
@ -2456,37 +2521,159 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
part = [parts objectAtIndex: i];
if ([[[part contentType] type] isEqualToString: @"text"])
if ([[[part contentType] type] isEqualToString: @"multipart"] && [[[part contentType] subType] isEqualToString: @"alternative"])
{
[map setObject: [[part contentType] stringValue] forKey: @"content-type"];
bodyFromSmartForward = [part body];
break;
aparts = [[part body] parts];
for (j = 0; j < [aparts count]; j++)
{
apart = [aparts objectAtIndex: j];
if ([[[apart contentType] type] isEqualToString: @"text"] && [[[apart contentType] subType] isEqualToString: @"html"])
htmlPart = apart;
if ([[[apart contentType] type] isEqualToString: @"text"] && [[[apart contentType] subType] isEqualToString: @"plain"])
textPart = apart;
}
}
else
{
if ([[[part contentType] type] isEqualToString: @"text"] && [[[part contentType] subType] isEqualToString: @"html"])
htmlPart = part;
else if ([[[part contentType] type] isEqualToString: @"text"] && [[[part contentType] subType] isEqualToString: @"plain"])
textPart = part;
else
[attachments addObject: part];
}
}
}
else
{
[map setObject: [[messageFromSmartForward contentType] stringValue] forKey: @"content-type"];
bodyFromSmartForward = [messageFromSmartForward body];
if ([[[messageFromSmartForward contentType] type] isEqualToString: @"text"] && [[[messageFromSmartForward contentType] subType] isEqualToString: @"html"])
htmlPart = messageFromSmartForward;
else
textPart = messageFromSmartForward;
}
htmlComposition = [[ud mailComposeMessageType] isEqualToString: @"html"];
if (htmlComposition && htmlPart)
{
bodyFromSmartForward = [htmlPart body];
charset = [[htmlPart contentType] valueOfParameter: @"charset"];
isHTML = YES;
}
else if (!htmlComposition && !textPart)
{
bodyFromSmartForward = [htmlPart body];
charset = [[htmlPart contentType] valueOfParameter: @"charset"];
isHTML = YES;
}
else
{
bodyFromSmartForward = [textPart body];
charset = [[textPart contentType] valueOfParameter: @"charset"];
}
// We make sure everything is encoded in UTF-8.
if ([bodyFromSmartForward isKindOfClass: [NSData class]])
{
if (![charset length])
charset = @"utf-8";
s = [NSString stringWithData: bodyFromSmartForward usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
if (!s)
s = [[[NSString alloc] initWithData: bodyFromSmartForward encoding: NSISOLatin1StringEncoding] autorelease];
bodyFromSmartForward = s;
}
if (htmlComposition && !isHTML)
{
[map setObject: @"text/html; charset=utf-8" forKey: @"content-type"];
bodyFromSmartForward = [[bodyFromSmartForward stringByEscapingHTMLString] stringByConvertingCRLNToHTML];
}
else if (!htmlComposition && isHTML)
{
[map setObject: @"text/plain; charset=utf-8" forKey: @"content-type"];
bodyFromSmartForward = [bodyFromSmartForward htmlToText];
}
else if (htmlComposition && isHTML)
{
[map setObject: @"text/html; charset=utf-8" forKey: @"content-type"];
}
else
{
[map setObject: @"text/plain; charset=utf-8" forKey: @"content-type"];
}
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease];
[bodyPart setBody: bodyFromSmartForward];
if (isSmartForward && [[ud mailMessageForwarding] isEqualToString: @"attached"])
[bodyPart setBody: [bodyFromSmartForward dataUsingEncoding: NSUTF8StringEncoding]];
else
[bodyPart setBody: [[NSString stringWithFormat: @"%@%@", bodyFromSmartForward, [mailObject contentForEditing]] dataUsingEncoding: NSUTF8StringEncoding]];
[body addBodyPart: bodyPart];
// Second part
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: @"message/rfc822" forKey: @"content-type"];
[map setObject: @"8bit" forKey: @"content-transfer-encoding"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease];
data = [mailObject content];
fdata = [[NGMimeFileData alloc] initWithBytes:[data bytes]
length:[data length]];
// Add attachments
for (a = 0; a < [attachments count]; a++)
{
[body addBodyPart: [attachments objectAtIndex: a]];
}
// For a forward decide whether do it inline or as an attachment.
if (isSmartForward)
{
if ([[ud mailMessageForwarding] isEqualToString: @"attached"])
{
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: @"message/rfc822" forKey: @"content-type"];
[map setObject: @"8bit" forKey: @"content-transfer-encoding"];
[map addObject: [NSString stringWithFormat: @"attachment; filename=\"%@\"", [mailObject filenameForForward]] forKey: @"content-disposition"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader: map] autorelease];
data = [mailObject content];
fdata = [[NGMimeFileData alloc] initWithBytes: [data bytes] length: [data length]];
[bodyPart setBody: fdata];
RELEASE(fdata);
[body addBodyPart: bodyPart];
}
else
{
attachmentKeys = [mailObject fetchFileAttachmentKeys];
if ([attachmentKeys count])
{
id currentAttachment;
NGHashMap *response;
NSData *bodydata;
NSArray *paths;
paths = [attachmentKeys keysWithFormat: @"BODY[%{path}]"];
response = [[mailObject fetchParts: paths] objectForKey: @"RawResponse"];
for (a = 0; a < [attachmentKeys count]; a++)
{
currentAttachment = [attachmentKeys objectAtIndex: a];
bodydata = [[[response objectForKey: @"fetch"] objectForKey: [NSString stringWithFormat: @"body[%@]", [currentAttachment objectForKey: @"path"]]] valueForKey: @"data"];
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: [currentAttachment objectForKey: @"mimetype"] forKey: @"content-type"];
[map setObject: [currentAttachment objectForKey: @"encoding"] forKey: @"content-transfer-encoding"];
[map addObject: [NSString stringWithFormat: @"attachment; filename=\"%@\"", [currentAttachment objectForKey: @"filename"]] forKey: @"content-disposition"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader: map] autorelease];
fdata = [[NGMimeFileData alloc] initWithBytes:[bodydata bytes] length:[bodydata length]];
[bodyPart setBody: fdata];
RELEASE(fdata);
[body addBodyPart: bodyPart];
}
}
}
}
[bodyPart setBody: fdata];
RELEASE(fdata);
[body addBodyPart: bodyPart];
[messageToSend setBody: body];
generator = [[[NGMimeMessageGenerator alloc] init] autorelease];
@ -2510,6 +2697,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
//
// <?xml version="1.0"?>
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
// <SmartForward xmlns="ComposeMail:">
// <ClientId>C9FF94FE-EA40-473A-B3E2-AAEE94F753A4</ClientId>
// <SaveInSentItems/>
// <ReplaceMime/>
// <Source>
// <FolderId>mail/INBOX</FolderId>
// <ItemId>82</ItemId>
// </Source>
// <MIME>... the data ...</MIME>
// </SmartForward>
//
- (void) processSmartForward: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
{
[self _processSmartCommand: theDocumentElement
inResponse: theResponse
isSmartForward: YES];
}
//
// <?xml version="1.0"?>
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
@ -2527,11 +2737,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) processSmartReply: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
{
[self processSmartForward: theDocumentElement inResponse: theResponse];
[self _processSmartCommand: theDocumentElement
inResponse: theResponse
isSmartForward: NO];
}
//
//
//
@ -2550,7 +2760,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pool = [[NSAutoreleasePool alloc] init];
ASSIGN(context, theContext);
// Get the device ID, device type and "stash" them
deviceId = [[theRequest uri] deviceId];
[context setObject: deviceId forKey: @"DeviceId"];
@ -2613,6 +2823,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (d)
{
if (debugOn)
[self logWithFormat: @"EAS - request for device %@: %@", [context objectForKey: @"DeviceId"], [[[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding] autorelease]];
builder = [[[NSClassFromString(@"DOMSaxBuilder") alloc] init] autorelease];
dom = [builder buildFromData: d];
documentElement = [dom documentElement];
@ -2630,7 +2843,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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"])
if (([cmdName rangeOfString: @"ItemOperations" options: NSCaseInsensitiveSearch].location != NSNotFound) &&
([[theRequest headerForKey: @"MS-ASAcceptMultiPart"] isEqualToString:@"T"] || [[theRequest uri] acceptsMultiPart]))
[theResponse setHeader: @"application/vnd.ms-sync.multipart" forKey: @"Content-Type"];
else
[theResponse setHeader: @"application/vnd.ms-sync.wbxml" forKey: @"Content-Type"];
@ -2641,6 +2855,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[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.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
if (debugOn && [[theResponse content] length])
[self logWithFormat: @"EAS - response for device %@: %@", [context objectForKey: @"DeviceId"], [[[NSString alloc] initWithData: [[theResponse content] wbxml2xml] encoding: NSUTF8StringEncoding] autorelease]];
RELEASE(context);
RELEASE(pool);

View file

@ -49,6 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGImap4/NSString+Imap4.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOApplication.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeFileData.h>
@ -74,6 +75,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <SOGo/SOGoUser.h>
#include <SOGo/NSString+Utilities.h>
#import <Appointments/SOGoAptMailNotification.h>
typedef struct {
uint32_t dwLowDateTime;
uint32_t dwHighDateTime;
@ -216,6 +219,8 @@ struct GlobalObjectId {
NSEnumerator *e;
NSData *d;
BOOL ignore;
textParts = [self fetchPlainTextParts];
e = [textParts keyEnumerator];
plainKey = nil;
@ -224,6 +229,27 @@ struct GlobalObjectId {
while ((key = [e nextObject]))
{
// Walk the hierarchy up and check whether parents are of type mulipart - i.e. ignore message/rfc822
if ([key countOccurrencesOfString: @"."] > 0)
{
NSMutableArray *a;
a = [[[key componentsSeparatedByString: @"."] mutableCopy] autorelease];
ignore = NO;
while ([a count] > 0)
{
[a removeLastObject];
part = [self lookupInfoForBodyPart: [a componentsJoinedByString: @"."]];
if (![[part valueForKey: @"type"] isEqualToString: @"multipart"])
ignore = YES;
}
if (ignore)
continue;
}
part = [self lookupInfoForBodyPart: key];
type = [part valueForKey: @"type"];
subtype = [part valueForKey: @"subtype"];
@ -440,7 +466,7 @@ struct GlobalObjectId {
// We get the right part based on the preference
if (theType == 1 || theType == 2)
{
if ([type isEqualToString: @"text"])
if ([type isEqualToString: @"text"] && ![subtype isEqualToString: @"calendar"])
{
NSString *s, *charset;
@ -499,9 +525,37 @@ struct GlobalObjectId {
- (iCalCalendar *) calendarFromIMIPMessage
{
NSDictionary *part;
NSString *type, *subtype;
NSArray *parts;
int i;
type = [[[self bodyStructure] valueForKey: @"type"] lowercaseString];
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
// process mail of type text/calendar
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"calendar"])
{
iCalCalendar *calendar;
NSString *encoding;
NSData *calendarData;
encoding = [[[self bodyStructure] valueForKey: @"encoding"] lowercaseString];
calendarData = [[self fetchPlainTextParts] objectForKey: @""];
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
calendarData = [calendarData dataByDecodingBase64];
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
calendarData = [calendarData dataByDecodingQuotedPrintableTransferEncoding];
NS_DURING
calendar = [iCalCalendar parseSingleFromSource: calendarData];
NS_HANDLER
calendar = nil;
NS_ENDHANDLER
return calendar;
}
// We check if we have at least 2 parts and if one of them is a text/calendar
parts = [[self bodyStructure] objectForKey: @"parts"];
@ -596,7 +650,11 @@ struct GlobalObjectId {
// Importance
v = 0x1;
p = [[self mailHeaders] objectForKey: @"x-priority"];
value = [[self mailHeaders] objectForKey: @"x-priority"];
if ([value isKindOfClass: [NSArray class]])
p = [value lastObject];
else
p = value;
if (p)
{
@ -607,7 +665,12 @@ struct GlobalObjectId {
}
else
{
p = [[self mailHeaders] objectForKey: @"importance"];
value = [[self mailHeaders] objectForKey: @"importance"];
if ([value isKindOfClass: [NSArray class]])
p = [value lastObject];
else
p = value;
if ([p hasPrefix: @"High"]) v = 0x2;
else if ([p hasPrefix: @"Low"]) v = 0x0;
}
@ -676,18 +739,18 @@ struct GlobalObjectId {
[s appendFormat: @"<AllDayEvent xmlns=\"Email:\">%d</AllDayEvent>", ([event isAllDay] ? 1 : 0)];
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
// StartTime -- https://msdn.microsoft.com/en-us/library/ee203365%28v=exchg.80%29.aspx
if ([event startDate])
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationInContext: context]];
if ([event timeStampAsDate])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationInContext: context]];
else if ([event created])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationInContext: context]];
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
// EndTime -- https://msdn.microsoft.com/en-us/library/ee158628(v=exchg.80).aspx
if ([event endDate])
[s appendFormat: @"<EndTime xmlns=\"Email:\">%@</EndTime>", [[event endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<EndTime xmlns=\"Email:\">%@</EndTime>", [[event endDate] activeSyncRepresentationInContext: context]];
// FIXME: Single appointment - others are not supported right now
[s appendFormat: @"<InstanceType xmlns=\"Email:\">%d</InstanceType>", 0];
@ -735,7 +798,9 @@ struct GlobalObjectId {
[s appendFormat: @"<GlobalObjId xmlns=\"Email:\">%@</GlobalObjId>", [globalObjId activeSyncRepresentationInContext: context]];
// We set the right message type - we must set AS version to 14.1 for this
[s appendFormat: @"<MeetingMessageType xmlns=\"Email2:\">%d</MeetingMessageType>", 1];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
[s appendFormat: @"<MeetingMessageType xmlns=\"Email2:\">%d</MeetingMessageType>", 1];
[s appendString: @"</MeetingRequest>"];
// ContentClass
@ -762,6 +827,42 @@ struct GlobalObjectId {
nativeBodyType = 1;
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
if (calendar && !d)
{
WOApplication *app;
SOGoAptMailNotification *p;
NSString *pageName;
nativeBodyType = 2;
/* get WOApplication instance */
app = [WOApplication application];
/* create page name */
pageName = [NSString stringWithFormat: @"SOGoAptMail%@", @"Invitation"];
/* construct message content */
p = [app pageWithName: pageName inContext: context];
[p setApt: (iCalEvent *) [[calendar events] lastObject]];
if ([[ [[calendar events] lastObject] organizer] cn] && [[[ [[calendar events] lastObject] organizer] cn] length])
{
[p setOrganizerName: [[ [[calendar events] lastObject] organizer] cn]];
}
else
{
[p setOrganizerName: [[SOGoUser userWithLogin: owner] cn]];
}
if (preferredBodyType == 1 && nativeBodyType == 2)
d = [[[p getBody] htmlToText] dataUsingEncoding: NSUTF8StringEncoding];
else
{
preferredBodyType = 2;
d = [[p getBody] dataUsingEncoding: NSUTF8StringEncoding];
}
}
if (d)
{
@ -883,9 +984,18 @@ struct GlobalObjectId {
[s appendFormat: @"</Categories>"];
}
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.0"] ||
[[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
{
if ([self inReplyTo])
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self inReplyTo] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
else if ([self messageId])
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self messageId] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
}
// FIXME - support these in the future
//[s appendString: @"<ConversationId xmlns=\"Email2:\">foobar</ConversationId>"];
//[s appendString: @"<ConversationIndex xmlns=\"Email2:\">zot=</ConversationIndex>"];
// NativeBodyType -- http://msdn.microsoft.com/en-us/library/ee218276(v=exchg.80).aspx
// This is a required child element.

2695
ChangeLog

File diff suppressed because it is too large Load diff

View file

@ -167,9 +167,9 @@ Operating System Requirements
The following 32-bit and 64-bit operating systems are currently
supported by SOGo:
* Red Hat Enterprise Linux (RHEL) Server 5 and 6
* Community ENTerprise Operating System (CentOS) 5 and 6
* Debian GNU/Linux 5.0 (Lenny) to 7.0 (Wheezy)
* Red Hat Enterprise Linux (RHEL) Server 5, 6 and 7
* Community ENTerprise Operating System (CentOS) 5, 6 and 7
* Debian GNU/Linux 6.0 (Squeeze) to 8.0 (Jessie)
* Ubuntu 10.04 (Lucid) to 14.04 (Trusty)
Make sure the required components are started automatically at boot time
@ -194,7 +194,8 @@ Installation
This section will guide you through the installation of SOGo together
with its dependencies. The steps described here apply to an RPM-based
installation for a Red Hat or CentOS distribution.
installation for a Red Hat or CentOS 6 distribution. Most of these steps
should apply to all supported operating systems.
Software Downloads
~~~~~~~~~~~~~~~~~~
@ -566,17 +567,29 @@ usernames like this: `SOGoSuperUsernames = (<username1>[, <username2>, ...]);`
for SOGo. Possible values are:
[options="compact"]
* `Arabic`
* `Basque`
* `BrazilianPortuguese`
* `Catalan`
* `Czech`
* `Danish`
* `Dutch`
* `English`
* `Finnish`
* `French`
* `German`
* `Hungarian`
* `Icelandic`
* `Italian`
* `NorwegianBokmal`
* `NorwegianNynorsk`
* `Polish`
* `Russian`
* `Spanish`
* `Slovak`
* `SpanishSpain`
* `SpanishArgentina`
* `Swedish`
* `Ukrainian`
* `Welsh`
|D |SOGoNotifyOnPersonalModifications
@ -649,7 +662,7 @@ of 1 day by default.
|Parameter used to configure which languages are available from SOGo's
Web interface. Available languages are specified as an array of string.
The default value is: `( "Czech", "Welsh", "English", "Spanish", "French", "German", "Italian", "Hungarian", "Dutch", "BrazilianPortuguese", "Polish", "Russian", Ukrainian", "Swedish" )`
The default value is: `( "Arabic", "Basque", "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English", "SpanishSpain", "SpanishArgentina", "Finnish", "French", "German", "Icelandic", "Italian", "Hungarian", "BrazilianPortuguese", "NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak", "Ukrainian", "Swedish" )`
|D |SOGoHideSystemEMail
|Parameter used to control if SOGo should hide or not the system email
@ -843,7 +856,7 @@ source:
[cols="^3,>47,50a"]
|=======================================================================
.33+|D <|SOGoUserSources
.34+|D <|SOGoUserSources
|Parameter used to set the LDAP and/or SQL sources used for
authentication and global address books. Multiple sources can be
specified as an array of dictionaries. A dictionary that defines an LDAP
@ -2439,6 +2452,11 @@ Defaults to `0`, which means no overwrite is performed.
Setting this parameter to a value greater than `512` will
have unexpected behaviour with various ActiveSync clients.
|S |SOGoEASDebugEnabled
|Parameter used to log the complete request and response of every single
EAS command.
Defaults to `NO`, which means no logging is performed.
|=======================================================================
Please be aware of the following limitations:
@ -2693,6 +2711,13 @@ current version of SOGo from the previous release.
[cols="100a"]
|=======================================================================
h|2.3.0
|Run the shell script `sql-update-2.2.17_to_2.3.0.sh` or
`sql-update-2.2.17_to_2.3.0-mysql.sh` (if you use MySQL).
This will grow the "participant states" field of calendar quick tables to a larger
size and add the the "c_description" column to calendar quick tables.
h|2.2.8
|The configuration configuration parameters were renamed:

View file

@ -239,7 +239,7 @@ Red Hat Enterprise Linux v6 x86_64
If you are using Red Hat Enterprise Linux version 6 x86_64, packages
for Samba 4, OpenChange and SOGo and the SOGo OpenChange backend are
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend_nightly.html.
http://www.sogo.nu/english/downloads/backend.html.
In order to satisfy certain dependencies, you should also add the EPEL
source corresponding to your distribution and architecture. More
@ -266,32 +266,30 @@ from this guide.
[NOTE]
Samba4/OpenChange are not available for now on CentOS 5 i386/x86_64,
CentOS 6 i386 and CentOS 7.
and CentOS 7. On Debian-based systems, packages are available only on
the x86_64 platform.
Debian 7.0 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Debian 7 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOGo, OpenChange and the SOGo OpenChange backend are now
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html to setup your
apt sources.
For Samba 4, you need to use the _wheezy-backports_ repository. To do so, create
`/etc/apt/sources.list.d/backports.list`:
On Debian7, for some Samba 4 dependencies, you need to use the
_wheezy-backports_ repository. To do so, create
`/etc/apt/sources.list.d/backports.list` with the following
content:
deb http://http.debian.net/debian wheezy-backports main
On Ubuntu 12.04, you will also have to add the Wheezy sources:
deb http://ftp.us.debian.org/debian wheezy main
deb http://security.debian.org/ wheezy/updates main
Then install Samba 4 on top of an existing SOGo
installation:
----
apt-get update
apt-get -t wheezy-backports install samba samba-dev
apt-get install samba samba-dev
----
Once completed, install the packages related to OpenChange and the SOGo
@ -303,7 +301,12 @@ apt-get install openchangeserver \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb
python-mysqldb \
openchange-ocsmanager \
openchange-rpcproxy \
python-sievelib \
python-spyne \
python-rpclib
----
Once the packages are installed, refer to the _Configuration_ chapter
@ -315,10 +318,8 @@ disable the upstart check. For more details, refer to:
https://wiki.samba.org/index.php/Samba4/InitScript
Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~
For Ubuntu 14.04, you must not use the Debian Wheezy backports.
Debian 8 (Jessie) and Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html to setup your
@ -341,12 +342,26 @@ apt-get install openchangeserver \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb
python-mysqldb \
openchange-ocsmanager \
openchange-rpcproxy \
python-sievelib \
python-spyne \
python-rpclib
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
[NOTE]
The `ocsmanager.conf` and `rpcproxy.conf` are currently located in
`/etc/apache2/conf.d`. These should be moved to `/etc/apache2/conf-available`.
This is a packaging error that will soon be fixed.
[NOTE]
You might have to adjust the `rpcproxy.conf` configuration file to add the
`Require all granted` permission if you get Apache errors such as
`client denied by server configuration`.
Configuration
-------------
@ -390,6 +405,7 @@ Add the following parameters to the `[global]` section of the
----
### Configuration required by OpenChange server ###
dsdb:schema update allowed = true
dcerpc endpoint servers = epmapper, mapiproxy, dnsserver
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
@ -407,6 +423,7 @@ Your Samba 4 configuration file should look like this:
netbios name = sogo
passdb backend = samba4
### Configuration required by OpenChange server ###
dsdb:schema update allowed = true
dcerpc endpoint servers = +epmapper, +mapiproxy
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
@ -533,7 +550,7 @@ services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
`/etc/httpd/conf.d/rpcproxy.conf`.
For Debian-based distributions, these files can be found
in `/etc/apache2/conf.d/`.
in `/etc/apache2/conf.d/` or `/etc/apache2/conf-available`.
The configuration requires three Apache modules:  _mod_proxy_,
_mod_proxy_http_ and _mod_wsgi_. These are usually already installed but
@ -541,13 +558,17 @@ might need to be activated on Debian-based installations:
a2enmod proxy proxy_http wsgi
The OCS Manager and RPC Proxy configuration module can be enabled using:
a2enconf ocsmanager
a2enconf rpcproxy
On RHEL-based distributions, make sure the `LoadModule` directive is
uncommented in `/etc/httpd/conf.d/wsgi.conf` (or
`python26-mod_wsgi.conf` on RHELv5).
uncommented in `/etc/httpd/conf.d/wsgi.conf`.
The _reqtimeout_ apache module is known to cause problems when using the
default configuration shipped with Debian-based systems. On such
distributions, apache will close (HTTP/1.1 500) any HTTP request for
distributions, Apache will close (HTTP/1.1 500) any HTTP request for
which the HTTP body hasn't arrived in 10 seconds.
While this is arguably good practice with regular HTTP, it will disrupt
@ -567,9 +588,102 @@ On Debian-based distributions, do:
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
[NOTE]
Debian-based distributions are not supported anymore for
OCSManager/rpcproxy. Support will soon resume.
Finally, you must adjust the OCS Manager configuration file, which is
located in `/etc/ocsmanager/ocsmanager.ini`. You should enable LDAP-based
authentication in the `main` section and configure it accordingly. You should
also enable rpcproxy. You file should be similar to this one:
----
[DEFAULT]
debug = true
email_to = you@yourdomain.com
smtp_server = localhost
error_email_from = paste@localhost
[main]
auth = ldap
mapistore_root = /var/lib/samba/private
mapistore_data = /var/lib/samba/private/mapistore
debug = yes
[auth:file]
[auth:ldap]
host = ldap://127.0.0.1
port = 389
bind_dn = cn=administrator,cn=Users,dc=example,dc=com
bind_pw = %1OpenChange
basedn = cn=Users,dc=example,dc=com
[auth:single]
username = openchange
password = {SSHA}I6Hy5Wv0wuxyXvMBFWFQDVVN12_CLaX9
[server:main]
use = egg:Paste#http
host = 127.0.0.1
port = 5000
protocol_version = HTTP/1.1
[app:main]
use = egg:ocsmanager
full_stack = true
static_files = true
cache_dir = %(here)s/data
beaker.session.key = ocsmanager
beaker.session.secret = SDyKK3dKyDgW0mlpqttTMGU1f
app_instance_uuid = {ee533ebc-f266-49d1-ae10-d017ee6aa98c}
NTLMAUTHHANDLER_WORKDIR = /var/cache/ntlmauthhandler
SAMBA_HOST = 127.0.0.1
[rpcproxy:ldap]
host = localhost
port = 389
basedn = CN=Users,DC=example,DC=com
set debug = true
----
----
[autodiscover]
[autodiscover:rpcproxy]
enabled = true
[outofoffice]
[outofoffice:file]
sieve_script_path = /var/vmail/$domain/$user/sieve-script
sieve_script_path_mkdir = false
[outofoffice:managesieve]
secret = secret
[loggers]
keys = root
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s
----
Once completed, start the OCS Manager service:
/etc/init.d/openchange-ocsmanager start
Name Service Configuration for Web Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -1,7 +1,7 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 2.2.17a - March 2015</releaseinfo>
<subtitle>for version 2.2.17a</subtitle>
<date>2015-03-26</date>
<releaseinfo>Version 2.3.0 - June 2015</releaseinfo>
<subtitle>for version 2.3.0</subtitle>
<date>2015-06-01</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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

@ -13,6 +13,6 @@
// TODO have the build system take care of this
:release_version: 2.2.17a
:release_version: 2.3.0
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:

105
NEWS
View file

@ -1,18 +1,64 @@
master
------
2.3.0 (2015-06-01)
-------------------
New features
- Internet headers are now shown in Outlook (Zentyal)
Enhancements
- Synchronize events, contacts and tasks in reverse chronological order
- improved multipart handling using EAS
- added systemd startup script (PR#76)
- added Basque translation - thanks to Gorka Gonzalez
- updated Brazilian (Portuguese), Dutch, Norwegian (Bokmal), Polish, Russian, and Spanish (Spain) translations
- calendar sharing request support among different Outlook versions (Zentyal)
- improved sync speed from Outlook by non-reprocessing already downloaded unread mails (Zentyal)
- added support for sharing calendar invitations
- missing contact fields are now saved and available when sharing it (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) (Zentyal)
- appointment color and importance work now between Outlooks (Zentyal)
- synchronize events, contacts and tasks in reverse chronological order (Zentyal)
- during login, we now extract the domain from the user to accelerate authentication requests on sources
- make sure sure email invitations can always be read by EAS clients
- now able to print event/task's description (new components only) in the list view (#2881)
- now possible to log EAS commands using the SOGoEASDebugEnabled system defaults
- many improvements to EAS SmartReply/SmartForward commands
- event invitation response mails from Outlook are now sent
- mail subfolders created in WebMail are created when Outlook synchronises
- mail root folder created in WebMail (same level INBOX) are created on Outlook logon
Bug fixes
- Outlook clients can use reply all functionality on multidomain environment
- Optional attendes on events are now shown properly
2.2.17a-zentyal1 (2015-04-15)
--------------------
Bug fixes
- Do not share Outlook metadata between users with the same name and different domain
- now keep the BodyPreference for future EAS use and default to MIME if none set (#3146)
- EAS reply fix when message/rfc822 parts are included in the original mail (#3153)
- fixed yet an other potential crash during freebusy lookups during timezone changes
- fixed display of freebusy information in event attendees editor during timezone changes
- fixed timezone of MSExchange freebusy information
- fixed a potential EAS error with multiple email priority flags
- fixed paragraphs margins in HTML messages (#3163)
- fixed regression when loading the inbox for the first time
- fixed serialization of the PreventInvitationsWhitelist settings
- fixed md4 support (for NTLM password changes) with GNU TLS
- fixed edition of attachment URL in event/task editor
- sent mails are not longer in Drafts folder using Outlook (Zentyal)
- deleted mails are properly synced between Outlook profiles from the same account (Zentyal)
- does not create a mail folder in other user's mailbox (Zentyal)
- fix server-side crash with invalid events (Zentyal)
- fix setting permissions for a folder with several users (Zentyal)
- fix reception of calendar event invitations on optional attendees (Zentyal)
- fix server side crash parsing rtf without color table (Zentyal)
- weekly recurring events created in SOGo web interface are now shown in Outlook (Zentyal)
- fix exception modifications import in recurrence series (Zentyal)
- fix server side crash parsing rtf emails with images (with word97 format) (Zentyal)
- fix sender on importing email messages like event invitations (Zentyal)
- fix Outlook crashes when modifying the view of a folder (Zentyal)
- fix server side crash when reading some recurrence appointments (Zentyal)
- Outlook clients can use reply all functionality on multidomain environment (Zentyal)
- optional attendes on events are now shown properly (Zentyal)
- fixed the EAS maximum response size being per-folder, and not global
- now set MeetingMessageType only for EAS 14.1
- now correctly handle external invitations using EAS
- now correctly handle multiple email addresses in the GAL over EAS (#3102)
- now handle very large amount of participants correctly (#3175)
- fix message bodies not shown on some EAS devices (#3173)
- avoid appending the domain unconditionally when SOGoEnableDomainBasedUID is set to YES
- recurrent all day events are now shown properly in Outlook
2.2.17a (2015-03-15)
--------------------
@ -51,6 +97,7 @@ Bug fixes
- prevent potential freebusy lookup crashes during timezone changes with repetitive events
- improved GetItemEstimate to count all vasnished/deleted mails too
- improvements to EAS SyncKey handling to avoid missing mails (#3048, #3058)
- fixed EAS replies decoding from Outlook (#3123)
2.2.16 (2015-02-12)
-------------------
@ -73,42 +120,6 @@ Bug fixes
- 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-zentyal3 (2015-04-14)
------
New features
- Internet headers are now shown in Outlook
Enhancements
- Sharing request among different Outlook versions
- Improve sync speed from Outlook by non-reprocessing already downloaded unread mails
Bug fixes
- Sent mails are not longer in Drafts folder using Outlook
- Deleted mails are properly synced between Outlook profiles from the same account
- Does not create a mail folder in other user's mailbox
- Fix server-side crash with invalid events
- Fix setting permissions for a folder with several users
- Fix reception of calendar event invitations on optional attendees
- Fix server side crash parsing rtf without color table
- Weekly recurring events created in SOGo web interface are now shown in Outlook
- Fix exception modifications import in recurrence series
- Fix server side crash parsing rtf emails with images (with word97 format)
2.2.15-zentyal2 (2015-03-16)
----------------------------
Enhancements
- Give support to calendar sharing invitations
- Missing contact fields are now saved and available when sharing it
(Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary)
- Appointment color and importance work now between Outlooks
Bug fixes
- Fix sender on importing email messages like event invitations
- Fix Outlook crashes when modifying the view of a folder
- Fix server side crash when reading some recurrence appointments
2.2.15 (2015-01-30)
-------------------

View file

@ -125,9 +125,7 @@ $(SOGOBACKEND)_OBJC_FILES += \
\
RTFHandler.m \
\
Codepages.m \
\
NGImap4Connection+Monkeypatching.m
Codepages.m
$(SOGOBACKEND)_RESOURCE_FILES += \
@ -178,7 +176,7 @@ $(SOGOBACKEND)_LIB_DIRS += \
$(LIBMAPISTORE_LIBS)
ADDITIONAL_INCLUDE_DIRS += \
-Werror -Wall \
-Wall \
-DSAMBA_PRIVATE_DIR=@"\"$(SAMBA_PRIVATE_DIR)\"" \
$(LIBMAPI_CFLAGS) \
$(LIBMAPISTORE_CFLAGS) \

View file

@ -1,45 +0,0 @@
/* NGImap4Connection+Monkeypatching.h - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* 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
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __OpenChange_NGImap4Connection_Monkeypatching_H__
#define __OpenChange_NGImap4Connection_Monkeypatching_H__
#import <Foundation/NSArray.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGExtensions/NGHashMap.h>
@interface NGImap4Connection (Monkeypatching)
- (NSArray *) fetchUIDs: (NSArray *) _uids
inURL: (NSURL *) _url
parts: (NSArray *) _parts;
- (void) _mergeDict: (NSDictionary *) source
into: (NSMutableDictionary *) target;
- (void) _mergeNGHashMap: (NGMutableHashMap *) source
into: (NGMutableHashMap *) target;
@end
#endif // __OpenChange_NGImap4Connection_Monkeypatching_H__

View file

@ -1,153 +0,0 @@
/* NGImap4Connection+Monkeypatching.m - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* 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
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import "NGImap4Connection+Monkeypatching.h"
#import <Foundation/NSValue.h>
#import <Foundation/NSDictionary.h>
#import <NGExtensions/NSObject+Logs.h>
@implementation NGImap4Connection (Monkeypatching)
- (NSArray *) fetchUIDs: (NSArray *) _uids
inURL: (NSURL *) _url
parts: (NSArray *) _parts
{
// currently returns a dict?!
/*
Allowed fetch keys:
UID
BODY.PEEK[<section>]<<partial>>
BODY [this is the bodystructure, supported]
BODYSTRUCTURE [not supported yet!]
ENVELOPE [this is a parsed header, but does not include type]
FLAGS
INTERNALDATE
RFC822
RFC822.HEADER
RFC822.SIZE
RFC822.TEXT
*/
NSMutableDictionary *result = nil;
NSUInteger i, total, step = 1000;
if (_uids == nil || [_uids count] == 0)
return nil;
/* select folder */
if (![self selectFolder:_url])
return nil;
/* fetch parts */
total = [_uids count];
for (i = 0; i < total; i += step) {
NSRange range;
NSArray *partial_uids;
NSDictionary *partial_result;
range = NSMakeRange(i, (i + step) > total ? (total - i) : step);
partial_uids = [_uids subarrayWithRange: range];
/* We will only fetch "step" uids each time */
partial_result = [[self client] fetchUids:partial_uids parts:_parts];
if (![[partial_result valueForKey:@"result"] boolValue]) {
[self errorWithFormat: @"Error fetching %u uids for url: %@",
total, _url];
return nil;
}
if (result == nil) {
/* First iteration, first result */
result = [[partial_result mutableCopy] autorelease];
} else {
/* Merge partial_result into previous result */
[self _mergeDict: partial_result into: result];
}
}
return (id)result;
}
- (void) _mergeDict: (NSDictionary *) source
into: (NSMutableDictionary *) target
{
for (id key in [source keyEnumerator]) {
id obj, current_obj;
current_obj = [target objectForKey: key];
if (current_obj == nil) {
/* This should never happen but just in case... */
[self errorWithFormat: @"Error merging fetchUids results: "
@"nonexistent key %@ on current target", key];
continue;
}
obj = [source objectForKey: key];
if ([obj isKindOfClass: [NSArray class]]) {
NSArray *data, *current_data, *new_data;
data = obj;
current_data = current_obj;
new_data = [current_data arrayByAddingObjectsFromArray: data];
[target setObject: new_data forKey: key];
} else if ([obj isKindOfClass: [NGMutableHashMap class]]) {
[self _mergeNGHashMap: obj into: current_obj];
} else if ([obj isKindOfClass: [NSNumber class]]) {
if (obj != current_obj) {
[self errorWithFormat: @"Error merging fetchUids results: "
@"incorrect value for key %@: %@ != %@",
key, obj, current_obj];
}
} else {
[self errorWithFormat: @"Error merging fetchUids results: "
@"ignored %@ (%@) key", key, [key class]];
}
}
}
- (void) _mergeNGHashMap: (NGMutableHashMap *) source
into: (NGMutableHashMap *) target
{
for (id key in [source keyEnumerator]) {
NSArray *obj, *current_obj;
current_obj = [target objectsForKey: key];
if (current_obj == nil) {
/* This should never happen but just in case... */
[self errorWithFormat: @"Error merging fetchUids results: "
@"nonexistent key %@ on current target", key];
continue;
}
if ([current_obj count] == 1) {
/* Merge only results, that means fields with more than 1 object */
continue;
}
obj = [source objectsForKey: key];
[target addObjects: obj forKey: key];
}
}
@end

View file

@ -885,16 +885,16 @@ const unsigned short ansicpg874[256] = {
char *v = NULL;
if (fontInfo && fontInfo->name)
{
if (fontInfo->name.length < 128)
if ([fontInfo->name length] < 128)
{
int tag_size = 15 + fontInfo->name.length;
int tag_size = 15 + [fontInfo->name length];
v = calloc(tag_size, sizeof(char));
snprintf(v, tag_size, "<font face=\"%s\">", [fontInfo->name UTF8String]);
}
else
{
NSLog(@"RTFHandler: Font %u has %d chars length, parse error? "
"Ignored", font_index, fontInfo->name.length);
"Ignored", font_index, [fontInfo->name length]);
v = calloc(7, sizeof(char));
sprintf(v, "<font>");
}

View file

@ -131,7 +131,7 @@
},
{
columnName = c_partstates;
sqlType = "VARCHAR2(255)";
sqlType = "CLOB";
allowsNull = YES;
},
{
@ -154,5 +154,10 @@
sqlType = "INTEGER";
allowsNull = YES;
},
{
columnName = c_description;
sqlType = "CLOB";
allowsNull = YES;
}
);
}

View file

@ -131,7 +131,7 @@
},
{
columnName = c_partstates;
sqlType = "VARCHAR(255)";
sqlType = "TEXT";
allowsNull = YES;
},
{
@ -153,6 +153,11 @@
columnName = c_nextalarm;
sqlType = "INT";
allowsNull = YES;
},
{
columnName = c_description;
sqlType = "TEXT";
allowsNull = YES;
}
);
}

View file

@ -1075,6 +1075,12 @@ static NSCharacterSet *whitespaceCharSet = nil;
// FIXME: Data is not always utf-8.....
source = [[[NSString alloc] initWithData: _data encoding: encoding]
autorelease];
// We fallback to ISO-8859-1 string encoding
if (!source)
source = [[[NSString alloc] initWithData: _data encoding: NSISOLatin1StringEncoding]
autorelease];
if (!source)
{
e = (id)[SaxParseException exceptionWithName: @"SaxIOException"

View file

@ -0,0 +1,14 @@
[Unit]
Description=SOGo is a groupware server
After=network.target
[Service]
Environment="PREFORK=3"
EnvironmentFile=-/etc/sysconfig/sogo
Type=forking
ExecStart=/usr/sbin/sogod -WOWorkersCount ${PREFORK} -WOPidFile /var/run/sogo/sogo.pid -WOLogFile /var/log/sogo/sogo.log
PIDFile=/var/run/sogo/sogo.pid
User=sogo
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,59 @@
#!/bin/bash
set -e
# This script only works with MySQL
# updates c_partstates to mediumtext
# adds c_description to Calendar quick tables
# http://www.sogo.nu/bugs/view.php?id=3175
# the field length was actually changed in v2.2.18
defaultusername=$USER
defaulthostname=127.0.0.1
defaultdatabase=$USER
indextable=$(sogo-tool dump-defaults -f /etc/sogo/sogo.conf | awk -F\" '/ OCSFolderInfoURL =/ {print $2}' | awk -F/ '{print $NF}')
if [ -z "$indextable" ]; then
echo "Couldn't fetch OCSFolderInfoURL value, aborting" >&2
exit 1
fi
read -p "Username ($defaultusername): " username
read -p "Hostname ($defaulthostname): " hostname
read -p "Database ($defaultdatabase): " database
if [ -z "$username" ]
then
username=$defaultusername
fi
if [ -z "$hostname" ]
then
hostname=$defaulthostname
fi
if [ -z "$database" ]
then
database=$defaultdatabase
fi
sqlscript=""
function adjustSchema() {
oldIFS="$IFS"
IFS=" "
part1="`echo -e \"ALTER TABLE $table MODIFY c_partstates mediumtext;\\n\"`";
part2="`echo -e \"ALTER TABLE $table ADD COLUMN c_description mediumtext;\\n\"`";
sqlscript="$sqlscript$part1$part2"
IFS="$oldIFS"
}
echo "This script will ask for the sql password twice" >&2
echo "Converting c_partstates from VARCHAR(255) to mediumtext in calendar quick tables" >&2
tables=`mysql -p -s -u $username -h $hostname $database -e "select SUBSTRING_INDEX(c_quick_location, '/', -1) from $indextable where c_path3 = 'Calendar';"`
for table in $tables;
do
adjustSchema
done
echo "$sqlscript" | mysql -p -s -u $username -h $hostname $database

View file

@ -0,0 +1,56 @@
#!/bin/bash
set -e
# This script only works with PostgreSQL
# updates c_partstates to text
# adds c_description to Calendar quick tables
# http://www.sogo.nu/bugs/view.php?id=3175
# the field length was actually changed in v2.2.18
defaultusername=$USER
defaulthostname=localhost
defaultdatabase=$USER
#indextable=sogo_folder_info
indextable=$(sogo-tool dump-defaults -f /etc/sogo/sogo.conf | awk -F\" '/ OCSFolderInfoURL =/ {print $2}' | awk -F/ '{print $NF}')
if [ -z "$indextable" ]; then
echo "Couldn't fetch OCSFolderInfoURL value, aborting" >&2
exit 1
fi
read -p "Username ($defaultusername): " username
read -p "Hostname ($defaulthostname): " hostname
read -p "Database ($defaultdatabase): " database
if [ -z "$username" ]
then
username=$defaultusername
fi
if [ -z "$hostname" ]
then
hostname=$defaulthostname
fi
if [ -z "$database" ]
then
database=$defaultdatabase
fi
sqlscript=""
function adjustSchema() {
oldIFS="$IFS"
IFS=" "
part1="`echo -e \"ALTER TABLE $table ALTER COLUMN c_partstates TYPE TEXT;\\n\"`";
part2="`echo -e \"ALTER TABLE $table ADD COLUMN c_description TEXT;\\n\"`";
sqlscript="$sqlscript$part1$part2"
IFS="$oldIFS"
}
echo "Converting c_cycleinfo from VARCHAR(255) to TEXT in calendar quick tables" >&2
tables=`psql -t -U $username -h $hostname $database -c "select split_part(c_quick_location, '/', 5) from $indextable where c_path3 = 'Calendar';"`
for table in $tables;
do
adjustSchema
done
echo "$sqlscript" | psql -q -e -U $username -h $hostname $database

View file

@ -0,0 +1,67 @@
"Inviting the following persons is prohibited:" = "Ondorengo pertsonak gonbidatzea debekatuta dago:";
"Personal Calendar" = "Egutegi pertsonala";
vevent_class0 = "(Ekitaldi publikoa)";
vevent_class1 = "(Ekitaldi pribatua)";
vevent_class2 = "(Isilpeko ekitaldia)";
vtodo_class0 = "(Zeregin publikoa)";
vtodo_class1 = "(Zeregin pribatua)";
vtodo_class2 = "(Isilpeko egitekoa)";
/* Receipts */
"The event \"%{Summary}\" was created" = "\"%{Summary}\" ekitaldia sortu da";
"The event \"%{Summary}\" was deleted" = "\"%{Summary}\" ekitaldia ezabatu da";
"The event \"%{Summary}\" was updated" = "\"%{Summary}\" ekitaldia eguneratu da";
"The following attendees(s) were notified:" = "Ondorengo partaidea(k) jakinarazi d(ir)a:";
"The following attendees(s) were added:" = "Ondorengo partaidea(k) gehitu d(ir)a:";
"The following attendees(s) were removed:" = "Ondorengo partaidea(k) ezabatu d(ir)a:";
/* IMIP messages */
"calendar_label" = "Egutegia";
"startDate_label" = "Hasi:";
"endDate_label" = "Amaitu:";
"due_label" = "Epemuga:";
"location_label" = "Kokapena:";
"summary_label" = "Laburpena:";
"comment_label" = "Iruzkina:";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Ekitaldirako gonbidapena: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(%{SentBy}-k bidalia) ";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}-k gonbidatu zaitu %{Summary}.-ra\n\nHasiera: %{StartDate}\nAmaiera: %{EndDate}\nDeskribapena: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}-k gonbidatu zaitu %{Summary}-ra \n\nHasiera: %{StartDate}-an, %{StartTime}-tan\nEnd: %{EndDate}-an, %{EndTime}-tan\nDeskribapena: %{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Ekitaldia bertan behera utzi da: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} ekitaldi hau bertan behera utzi du: %{Summary}.\n\nHasiera: %{StartDate}\nAmaiera: %{EndDate}\nDEskribapena: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText}-k honako ekitaldia bertan behera utzi du: %{Summary}.\n\nHasiera: %{StartDate}-an, %{StartTime}-tan\nAmaiera: %{EndDate}-an %{EndTime}-tan\nDeskribapena: %{Description}";
/* Update */
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
= "%{OldStartDate} eguneko \"%{Summary}\" hitzordua aldatu da";
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
= "%{OldStartDate} eguneko eta %{OldStartTime} orduko \"%{Summary}\" hitzordua aldatu da";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= " \"%{Summary}\" bilerako ondorengo parametroak aldatu dira:";
"Please accept or decline those changes."
= "Mesedez, onartu edo ezetsi ondorengo aldaketak.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Gonbidapena onartua: \"%{Summary}\"";
"Declined invitation: \"%{Summary}\"" = "Ezetzitako gonbidapena: \"%{Summary}\"";
"Delegated invitation: \"%{Summary}\"" = "Delegatutako gonbidapena: \"%{Summary}\"";
"Not yet decided on invitation: \"%{Summary}\"" = "\"%{Summary}\" gonbidapenari buruz erabaki gabe";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText} -k zure gonbidapena onartu du.";
"%{Attendee} %{SentByText}has declined your event invitation."
= "%{Attendee} %{SentByText}-k zure gonbidapenari uko egin dio.";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "%{Attendee} %{SentByText}-k zure gonbidapena %{Delegate}-ri delegatu dio.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
= "%{Attendee} %{SentByText}-k ez du oraindik zure gonbidapenari buruz erabakirik hartu.";
/* Resources */
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Ezin da honako baliabidea atzitu: \"%{Cn} %{SystemEmail}\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "\"%{Cn} %{SystemEmail}\" baliabidearentzako gehienezko erreserba kopurura (%{NumberOfSimultaneousBookings}) iritsi gara. Gatazka sortu duen ekitaldia \"%{EventTitle}\" da, eta %{StartDate}-n hasten da.";

View file

@ -56,7 +56,7 @@ vtodo_class2 = "(Tarefa Confidencial)";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText}foi aceitado seu convite ao evento.";
"%{Attendee} %{SentByText}has declined your event invitation."
= "%{Attendee} %{SentByText}foi declinado seu convite ao evento.";
= "%{Attendee} %{SentByText}recusou seu convite para o evento.";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "%{Attendee} %{SentByText} delegou o convite para %{Delegate}.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."

View file

@ -54,7 +54,7 @@ Appointments_RESOURCE_FILES += \
MSExchangeFreeBusySOAPResponseMap.plist \
MSExchangeFreeBusySOAPRequest.wo
Appointments_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Appointments_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Appointments_LOCALIZED_RESOURCE_FILES = Localizable.strings

View file

@ -70,11 +70,27 @@
to: (NSCalendarDate *) newEndDate
{
ASSIGN(address, newAddress);
ASSIGN(startDate, newStartDate);
ASSIGN(endDate, newEndDate);
startDate = [NSCalendarDate dateWithYear: [newStartDate yearOfCommonEra]
month: [newStartDate monthOfYear]
day: [newStartDate dayOfMonth]
hour: [newStartDate hourOfDay]
minute: [newStartDate minuteOfHour]
second: [newStartDate secondOfMinute]
timeZone: [newStartDate timeZone]];
endDate = [NSCalendarDate dateWithYear: [newEndDate yearOfCommonEra]
month: [newEndDate monthOfYear]
day: [newEndDate dayOfMonth]
hour: [newEndDate hourOfDay]
minute: [newEndDate minuteOfHour]
second: [newEndDate secondOfMinute]
timeZone: [newEndDate timeZone]];
[startDate setTimeZone: timeZone];
[endDate setTimeZone: timeZone];
[startDate retain];
[endDate retain];
}
- (NSString *) serverVersion

View file

@ -502,12 +502,12 @@ static Class iCalEventK = nil;
BOOL is_owner;
userLogin = [[context activeUser] login];
is_owner = [userLogin isEqualToString: [self ownerInContext: context]];
is_owner = [userLogin isEqualToString: self->owner];
// 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]];
forUser: [context activeUser]];
if ([self isSubscription])
{
@ -800,7 +800,7 @@ static Class iCalEventK = nil;
/**
* Set the timezone of the event start and end dates to the user's timezone.
* @param theRecord a dictionnary with the attributes of the event.
* @param theRecord a dictionary with the attributes of the event.
* @return a copy of theRecord with adjusted dates.
*/
- (NSMutableDictionary *) _fixupRecord: (NSDictionary *) theRecord
@ -2814,7 +2814,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
@"c_category", @"c_classification", @"c_isallday",
@"c_isopaque", @"c_participants", @"c_partmails",
@"c_partstates", @"c_sequence", @"c_priority",
@"c_cycleinfo", @"c_iscycle", @"c_nextalarm", nil];
@"c_cycleinfo", @"c_iscycle", @"c_nextalarm", @"c_description", nil];
return [self fetchFields: infos from: _startDate to: _endDate title: title
component: _component

View file

@ -421,11 +421,14 @@
SOGoUserSettings *us;
NSMutableArray *unavailableAttendees;
NSEnumerator *enumerator;
NSString *currentUID, *ownerUID, *whiteListString;
NSString *currentUID, *ownerUID;
NSMutableString *reason;
NSDictionary *values;
NSMutableDictionary *value, *moduleSettings, *whiteList;
NSMutableDictionary *value, *moduleSettings;
id whiteList;
int i, count;
i = count = 0;
// Build list of the attendees uids without ressources
@ -447,8 +450,11 @@
if (![user isResource] && [[moduleSettings objectForKey:@"PreventInvitations"] boolValue])
{
// Check if the user have a whiteList
whiteListString = [moduleSettings objectForKey:@"PreventInvitationsWhitelist"];
whiteList = [whiteListString objectFromJSONString];
whiteList = [moduleSettings objectForKey:@"PreventInvitationsWhitelist"];
// For backward <= 2.2.17 compatibility
if ([whiteList isKindOfClass: [NSString class]])
whiteList = [whiteList objectFromJSONString];
// If the filter have a hit, do not add the currentUID to the unavailableAttendees array
if (![whiteList objectForKey:ownerUID])

View file

@ -248,6 +248,12 @@
else
[row setObject: [NSNull null] forKey: @"c_category"];
/* handle description */
if ([self comment])
[row setObject: [self comment] forKey: @"c_description"];
else
[row setObject: [NSNull null] forKey: @"c_description"];
return row;
}

View file

@ -177,6 +177,12 @@
[row setObject: [categories componentsJoinedByString: @","]
forKey: @"c_category"];
/* handle description */
if ([self comment])
[row setObject: [self comment] forKey: @"c_description"];
else
[row setObject: [NSNull null] forKey: @"c_description"];
return row;
}

View file

@ -0,0 +1,2 @@
"Personal Address Book" = "Helbide liburu pertsonala";
"Collected Address Book" = "Bildutako helbide liburua";

View file

@ -1,2 +1,2 @@
"Personal Address Book" = "Livro de Endereços Pessoais";
"Personal Address Book" = "Livro de Endereço Pessoal";
"Collected Address Book" = "Catálogos Coletados";

View file

@ -27,7 +27,7 @@ Contacts_OBJC_FILES = \
Contacts_RESOURCE_FILES += \
product.plist \
Contacts_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Contacts_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Contacts_LOCALIZED_RESOURCE_FILES = Localizable.strings

View file

@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Beste erabiltzaileak";
"SharedFoldersName" = "Partekatutako karpetak";

View file

@ -92,7 +92,7 @@ Mailer_RESOURCE_FILES += \
SOGoMailWelshReply.wo
Mailer_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Mailer_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Mailer_LOCALIZED_RESOURCE_FILES = Localizable.strings

View file

@ -0,0 +1,16 @@
<#newLine/>
<#newLine/>
<#signaturePlacementOnTop><#newLine/>
<#signature/><#newLine/></#signaturePlacementOnTop>
-------- Original Message --------<#newLine/>
Gaia: <#subject/><#newLine/>
Data: <#date/><#newLine/>
Nork: <#from/><#newLine/>
<#hasReplyTo>Erantzun-honi: <#replyTo/></#hasReplyTo><#hasOrganization>Erakundea: <#organization/></#hasOrganization>Nori: <#to/><#newLine/>
<#hasCc>Kopia: <#cc/></#hasCc><#hasNewsGroups>Berri-taldeak: <#newsgroups/></#hasNewsGroups><#hasReferences>Erreferentziak: <#references/></#hasReferences><#newLine/>
<#newLine/>
<#messageBody/><#newLine/>
<#signaturePlacementOnBottom><#newLine/>
<#newLine/>
<#signature/></#signaturePlacementOnBottom>
<#newLine/>

View file

@ -0,0 +1,97 @@
subject: WOString {
value = subject;
escapeHTML = NO;
}
date: WOString {
value = date;
escapeHTML = NO;
}
from: WOString {
value = from;
escapeHTML = NO;
}
newLine: WOString {
value = newLine;
escapeHTML = NO;
}
hasReplyTo: WOConditional {
condition = hasReplyTo;
}
replyTo: WOString {
value = replyTo;
escapeHTML = NO;
}
hasOrganization: WOConditional {
condition = hasOrganization;
}
organization: WOString {
value = organization;
escapeHTML = NO;
}
to: WOString {
value = to;
escapeHTML = NO;
}
hasCc: WOConditional {
condition = hasCc;
}
cc: WOString {
value = cc;
escapeHTML = NO;
}
hasNewsGroups: WOConditional {
condition = hasNewsGroups;
}
newsgroups: WOString {
value = newsgroups;
escapeHTML = NO;
}
hasReferences: WOConditional {
condition = hasReferences;
}
references: WOString {
value = references;
escapeHTML = NO;
}
messageBody: WOString {
value = messageBody;
escapeHTML = NO;
}
signature: WOString {
value = signature;
escapeHTML = NO;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}

View file

@ -0,0 +1,16 @@
<#replyPlacementOnTop><#newLine/>
<#newLine/>
</#replyPlacementOnTop><#signaturePlacementOnTop><#newLine/>
<#signature/><#newLine/>
</#signaturePlacementOnTop><#outlookMode>-------- Jatorrizko Mezua --------<#newLine/>
Gaia: <#subject/><#newLine/>
Data: <#date/><#newLine/>
Nork: <#from/><#newLine/>
<#hasReplyTo>Erantzun-honi: <#replyTo/></#hasReplyTo><#hasOrganization>Erakundea: <#organization/></#hasOrganization>Nori: <#to/><#newLine/>
<#hasCc>Kopia: <#cc/></#hasCc><#hasNewsGroups>Berri-taldeak: <#newsgroups/></#hasNewsGroups><#hasReferences>Erreferentziak: <#references/></#hasReferences></#outlookMode><#newLine/>
<#standardMode><#date/>-an, <#from/>-k idatzi zuen:</#standardMode><#newLine/>
<#newLine/>
<#messageBody/><#newLine/>
<#replyPlacementOnBottom><#newLine/>
<#newLine/>
</#replyPlacementOnBottom><#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom><#newLine/>

View file

@ -0,0 +1,106 @@
outlookMode: WOConditional {
condition = outlookMode;
}
standardMode: WOConditional {
condition = outlookMode;
negate = YES;
}
subject: WOString {
value = subject;
escapeHTML = NO;
}
date: WOString {
value = date;
escapeHTML = NO;
}
from: WOString {
value = from;
escapeHTML = NO;
}
newLine: WOString {
value = newLine;
escapeHTML = NO;
}
hasReplyTo: WOConditional {
condition = hasReplyTo;
}
replyTo: WOString {
value = replyTo;
escapeHTML = NO;
}
hasOrganization: WOConditional {
condition = hasOrganization;
}
organization: WOString {
value = organization;
escapeHTML = NO;
}
to: WOString {
value = to;
escapeHTML = NO;
}
hasCc: WOConditional {
condition = hasCc;
}
cc: WOString {
value = cc;
escapeHTML = NO;
}
hasNewsGroups: WOConditional {
condition = hasNewsGroups;
}
newsgroups: WOString {
value = newsgroups;
escapeHTML = NO;
}
hasReferences: WOConditional {
condition = hasReferences;
}
references: WOString {
value = references;
escapeHTML = NO;
}
messageBody: WOString {
value = messageBody;
escapeHTML = NO;
}
signature: WOString {
value = signature;
escapeHTML = NO;
}
replyPlacementOnTop: WOConditional {
condition = replyPlacementOnTop;
}
replyPlacementOnBottom: WOConditional {
condition = replyPlacementOnTop;
negate = YES;
}
signaturePlacementOnTop: WOConditional {
condition = signaturePlacementOnTop;
}
signaturePlacementOnBottom: WOConditional {
condition = signaturePlacementOnTop;
negate = YES;
}

View file

@ -384,6 +384,11 @@ static BOOL debugSoParts = NO;
_path = [_path componentsSeparatedByString: @"."];
}
// deal with mails of type text/calendar
if ([[[info valueForKey: @"type"] lowercaseString] isEqualToString: @"text"] &&
[[[info valueForKey: @"subtype"] lowercaseString] isEqualToString: @"calendar"])
return info;
/*
For each path component, eg 1,1,3
@ -772,6 +777,8 @@ static BOOL debugSoParts = NO;
filename = [NSString stringWithFormat: @"unknown_%@", path];
else if ([mimeType isEqualToString: @"message/rfc822"])
filename = [NSString stringWithFormat: @"email_%@.eml", path];
else if ([mimeType isEqualToString: @"text/calendar"])
filename = [NSString stringWithFormat: @"calendar_%@.ics", path];
if (filename)

View file

@ -1,2 +0,0 @@
config.h
md4.c

View file

@ -159,7 +159,7 @@ SOGo_OBJC_FILES = \
\
SOGoCredentialsFile.m
SOGo_C_FILES = lmhash.c
SOGo_C_FILES += lmhash.c
SOGo_RESOURCE_FILES = \
SOGoDefaults.plist \

View file

@ -30,8 +30,7 @@ SOGo_LIBRARIES_DEPEND_UPON += \
ifeq ($(HAS_LIBRARY_gnutls),yes)
ADDITIONAL_CPPFLAGS += -DHAVE_GNUTLS=1
SOGo_LIBRARIES_DEPEND_UPON += -lgnutls
ADDITIONAL_INCLUDE_DIRS += -I$(GNULIB_INCLUDE)
SOGo_C_FILES += $(GNULIB_FILES)
SOGo_C_FILES += md4.c
else
ifeq ($(HAS_LIBRARY_ssl),yes)
ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1

View file

@ -737,7 +737,7 @@ groupObjectClasses: (NSArray *) newGroupObjectClasses
}
NS_HANDLER
{
if ([[localException name] isEqual: @"LDAPException"] &&
if ([[localException name] isEqual: @"LDAPException"] &&
([[[localException userInfo] objectForKey: @"error_code"] intValue] == LDAP_CONSTRAINT_VIOLATION))
{
*perr = PolicyInsufficientPasswordQuality;

View file

@ -39,7 +39,7 @@
#include <stdint.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <md4.h>
#include "md4.h"
#define MD4_DIGEST_LENGTH 16
#define MD5_DIGEST_LENGTH 16
#define SHA_DIGEST_LENGTH 20
@ -54,6 +54,8 @@
#error this module requires either gnutls or openssl
#endif
#include "lmhash.h"
#import <Foundation/NSArray.h>
#import <NGExtensions/NGBase64Coding.h>
#import "NSData+Crypto.h"

View file

@ -39,7 +39,7 @@
SOGoLoginModule = "Mail";
SOGoLanguage = "English";
SOGoSupportedLanguages = ( "Arabic", "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English",
SOGoSupportedLanguages = ( "Arabic", "Basque", "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English",
"SpanishSpain", "SpanishArgentina", "Finnish", "French", "German",
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak",

View file

@ -262,9 +262,7 @@
// The domain is probably appended to the username;
// make sure it is defined as a domain in the configuration.
*theDomain = [*theLogin substringFromIndex: (r.location + r.length)];
if ([[sd domainIds] containsObject: *theDomain])
*theLogin = [*theLogin substringToIndex: r.location];
else
if (![[sd domainIds] containsObject: *theDomain])
*theDomain = nil;
}
}

View file

@ -1,6 +1,6 @@
/* SOGoSystemDefaults.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
@ -64,6 +64,8 @@
- (BOOL) uixAdditionalPreferences;
- (BOOL) uixDebugEnabled;
- (BOOL) easDebugEnabled;
- (NSString *) pageTitle;
- (NSArray *) supportedLanguages;

View file

@ -1,6 +1,6 @@
/* SOGoSystemDefaults.m - this file is part of SOGo
*
* Copyright (C) 2009-2014 Inverse inc.
* Copyright (C) 2009-2015 Inverse inc.
* Copyright (C) 2012 Jeroen Dekkers <jeroen@dekkers.ch>
*
* This file is free software; you can redistribute it and/or modify
@ -427,6 +427,11 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
return [self boolForKey: @"SOGoUIxDebugEnabled"];
}
- (BOOL) easDebugEnabled
{
return [self boolForKey: @"SOGoEASDebugEnabled"];
}
- (NSString *) pageTitle
{
return [self stringForKey: @"SOGoPageTitle"];

View file

@ -504,16 +504,49 @@ static Class NSNullK;
SOGoSystemDefaults *dd;
BOOL checkOK;
if (*_domain && [_login rangeOfString: @"@"].location == NSNotFound)
username = [NSString stringWithFormat: @"%@@%@", _login, *_domain];
dd = [SOGoSystemDefaults sharedSystemDefaults];
username = _login;
if (*_domain)
{
if ([_login rangeOfString: @"@"].location == NSNotFound)
username = [NSString stringWithFormat: @"%@@%@", _login, *_domain];
}
else
username = _login;
{
NSRange r;
// We try to extract the domain in use in order to avoid pounding all the authentication
// sources if SOGoLoginDomains isn't specified. This is also true if the user is
// using DAV or EAS.
r = [username rangeOfString: @"@"];
if (r.location != NSNotFound)
{
NSArray *allDomains;
int i;
*_domain = [username substringFromIndex: r.location+1];
allDomains = [[dd dictionaryForKey: @"domains"] allValues];
for (i = 0; i < [allDomains count]; i++)
{
if ([*_domain isEqualToString: [[allDomains objectAtIndex: i] objectForKey: @"SOGoMailDomain"]])
break;
}
// We haven't found one
if (i == [allDomains count])
*_domain = nil;
}
}
// We check the fail count per user in memcache (per server). If the
// fail count reaches X in Y minutes, we deny immediately the
// authentications for Z minutes
failedCount = [[SOGoCache sharedCache] failedCountForLogin: username];
dd = [SOGoSystemDefaults sharedSystemDefaults];
if (failedCount)
{
unsigned int current_time, start_time, delta, block_time;

381
SoObjects/SOGo/md4.c Normal file
View file

@ -0,0 +1,381 @@
/* Functions to compute MD4 message digest of files or memory blocks.
according to the definition of MD4 in RFC 1320 from April 1992.
Copyright (C) 1995-1997, 1999-2003, 2005-2006, 2008-2011 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Adapted by Simon Josefsson from gnulib md5.? and Libgcrypt
cipher/md4.c . */
#include "md4.h"
#include <stdalign.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#if USE_UNLOCKED_IO
# include "unlocked-io.h"
#endif
#ifdef WORDS_BIGENDIAN
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#else
# define SWAP(n) (n)
#endif
#define BLOCKSIZE 32768
#if BLOCKSIZE % 64 != 0
# error "invalid BLOCKSIZE"
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1320, 3.1: Step 1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/* Initialize structure containing state of computation.
(RFC 1320, 3.3: Step 3) */
void
md4_init_ctx (struct md4_ctx *ctx)
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Copy the 4 byte value from v into the memory location pointed to by *cp,
If your architecture allows unaligned access this is equivalent to
* (uint32_t *) cp = v */
static inline void
set_uint32 (char *cp, uint32_t v)
{
memcpy (cp, &v, sizeof v);
}
/* Put result from CTX in first 16 bytes following RESBUF. The result
must be in little endian byte order. */
void *
md4_read_ctx (const struct md4_ctx *ctx, void *resbuf)
{
char *r = resbuf;
set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A));
set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B));
set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C));
set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D));
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */
void *
md4_finish_ctx (struct md4_ctx *ctx, void *resbuf)
{
/* Take yet unprocessed bytes into account. */
uint32_t bytes = ctx->buflen;
size_t pad;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy (&((char*)ctx->buffer)[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
ctx->buffer[(bytes + pad) / 4] = SWAP (ctx->total[0] << 3);
ctx->buffer[(bytes + pad) / 4 + 1] = SWAP ((ctx->total[1] << 3) |
(ctx->total[0] >> 29));
/* Process last bytes. */
md4_process_block (ctx->buffer, bytes + pad + 8, ctx);
return md4_read_ctx (ctx, resbuf);
}
/* Compute MD4 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 16 bytes
beginning at RESBLOCK. */
int
md4_stream (FILE * stream, void *resblock)
{
struct md4_ctx ctx;
size_t sum;
char *buffer = malloc (BLOCKSIZE + 72);
if (!buffer)
return 1;
/* Initialize the computation context. */
md4_init_ctx (&ctx);
/* Iterate over full file contents. */
while (1)
{
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
computation function processes the whole buffer so that with the
next round of the loop another block can be read. */
size_t n;
sum = 0;
/* Read block. Take care for partial reads. */
while (1)
{
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
sum += n;
if (sum == BLOCKSIZE)
break;
if (n == 0)
{
/* Check for the error flag IFF N == 0, so that we don't
exit the loop after a partial read due to e.g., EAGAIN
or EWOULDBLOCK. */
if (ferror (stream))
{
free (buffer);
return 1;
}
goto process_partial_block;
}
/* We've read at least one byte, so ignore errors. But always
check for EOF, since feof may be true even though N > 0.
Otherwise, we could end up calling fread after EOF. */
if (feof (stream))
goto process_partial_block;
}
/* Process buffer with BLOCKSIZE bytes. Note that
BLOCKSIZE % 64 == 0
*/
md4_process_block (buffer, BLOCKSIZE, &ctx);
}
process_partial_block:;
/* Process any remaining bytes. */
if (sum > 0)
md4_process_bytes (buffer, sum, &ctx);
/* Construct result in desired memory. */
md4_finish_ctx (&ctx, resblock);
free (buffer);
return 0;
}
/* Compute MD4 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
void *
md4_buffer (const char *buffer, size_t len, void *resblock)
{
struct md4_ctx ctx;
/* Initialize the computation context. */
md4_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
md4_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return md4_finish_ctx (&ctx, resblock);
}
void
md4_process_bytes (const void *buffer, size_t len, struct md4_ctx *ctx)
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&((char*)ctx->buffer)[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64)
{
md4_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer, &((char*)ctx->buffer)[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64)
{
#if !_STRING_ARCH_unaligned
# define UNALIGNED_P(p) ((uintptr_t) (p) % alignof (uint32_t) != 0)
if (UNALIGNED_P (buffer))
while (len > 64)
{
md4_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
else
#endif
{
md4_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy (&((char*)ctx->buffer)[left_over], buffer, len);
left_over += len;
if (left_over >= 64)
{
md4_process_block (ctx->buffer, 64, ctx);
left_over -= 64;
memcpy (ctx->buffer, &ctx->buffer[16], left_over);
}
ctx->buflen = left_over;
}
}
/* --- Code below is the primary difference between md5.c and md4.c --- */
/* MD4 round constants */
#define K1 0x5a827999
#define K2 0x6ed9eba1
/* Round functions. */
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n))))
#define R1(a,b,c,d,k,s) a=rol(a+F(b,c,d)+x[k],s);
#define R2(a,b,c,d,k,s) a=rol(a+G(b,c,d)+x[k]+K1,s);
#define R3(a,b,c,d,k,s) a=rol(a+H(b,c,d)+x[k]+K2,s);
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. */
void
md4_process_block (const void *buffer, size_t len, struct md4_ctx *ctx)
{
const uint32_t *words = buffer;
size_t nwords = len / sizeof (uint32_t);
const uint32_t *endp = words + nwords;
uint32_t x[16];
uint32_t A = ctx->A;
uint32_t B = ctx->B;
uint32_t C = ctx->C;
uint32_t D = ctx->D;
/* First increment the byte count. RFC 1320 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (words < endp)
{
int t;
for (t = 0; t < 16; t++)
{
x[t] = SWAP (*words);
words++;
}
/* Round 1. */
R1 (A, B, C, D, 0, 3);
R1 (D, A, B, C, 1, 7);
R1 (C, D, A, B, 2, 11);
R1 (B, C, D, A, 3, 19);
R1 (A, B, C, D, 4, 3);
R1 (D, A, B, C, 5, 7);
R1 (C, D, A, B, 6, 11);
R1 (B, C, D, A, 7, 19);
R1 (A, B, C, D, 8, 3);
R1 (D, A, B, C, 9, 7);
R1 (C, D, A, B, 10, 11);
R1 (B, C, D, A, 11, 19);
R1 (A, B, C, D, 12, 3);
R1 (D, A, B, C, 13, 7);
R1 (C, D, A, B, 14, 11);
R1 (B, C, D, A, 15, 19);
/* Round 2. */
R2 (A, B, C, D, 0, 3);
R2 (D, A, B, C, 4, 5);
R2 (C, D, A, B, 8, 9);
R2 (B, C, D, A, 12, 13);
R2 (A, B, C, D, 1, 3);
R2 (D, A, B, C, 5, 5);
R2 (C, D, A, B, 9, 9);
R2 (B, C, D, A, 13, 13);
R2 (A, B, C, D, 2, 3);
R2 (D, A, B, C, 6, 5);
R2 (C, D, A, B, 10, 9);
R2 (B, C, D, A, 14, 13);
R2 (A, B, C, D, 3, 3);
R2 (D, A, B, C, 7, 5);
R2 (C, D, A, B, 11, 9);
R2 (B, C, D, A, 15, 13);
/* Round 3. */
R3 (A, B, C, D, 0, 3);
R3 (D, A, B, C, 8, 9);
R3 (C, D, A, B, 4, 11);
R3 (B, C, D, A, 12, 15);
R3 (A, B, C, D, 2, 3);
R3 (D, A, B, C, 10, 9);
R3 (C, D, A, B, 6, 11);
R3 (B, C, D, A, 14, 15);
R3 (A, B, C, D, 1, 3);
R3 (D, A, B, C, 9, 9);
R3 (C, D, A, B, 5, 11);
R3 (B, C, D, A, 13, 15);
R3 (A, B, C, D, 3, 3);
R3 (D, A, B, C, 11, 9);
R3 (C, D, A, B, 7, 11);
R3 (B, C, D, A, 15, 15);
A = ctx->A += A;
B = ctx->B += B;
C = ctx->C += C;
D = ctx->D += D;
}
}

91
SoObjects/SOGo/md4.h Normal file
View file

@ -0,0 +1,91 @@
/* Declarations of functions and data types used for MD4 sum
library functions.
Copyright (C) 2000-2001, 2003, 2005, 2008-2011 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef MD4_H
# define MD4_H 1
# include <stdio.h>
# include <stdint.h>
# ifdef __cplusplus
extern "C" {
# endif
# define MD4_DIGEST_SIZE 16
/* Structure to save state of computation between the single steps. */
struct md4_ctx
{
uint32_t A;
uint32_t B;
uint32_t C;
uint32_t D;
uint32_t total[2];
uint32_t buflen;
uint32_t buffer[32];
};
/* Initialize structure containing state of computation. */
extern void md4_init_ctx (struct md4_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */
extern void md4_process_block (const void *buffer, size_t len,
struct md4_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void md4_process_bytes (const void *buffer, size_t len,
struct md4_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX
in first 16 bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest. */
extern void *md4_finish_ctx (struct md4_ctx *ctx, void *resbuf);
/* Put result from CTX in first 16 bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest. */
extern void *md4_read_ctx (const struct md4_ctx *ctx, void *resbuf);
/* Compute MD4 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 16 bytes
beginning at RESBLOCK. */
extern int md4_stream (FILE * stream, void *resblock);
/* Compute MD4 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *md4_buffer (const char *buffer, size_t len, void *resblock);
# ifdef __cplusplus
}
# endif
#endif

13
TODO
View file

@ -1,13 +0,0 @@
Rendering of multi-status responses is suboptimal in SOPE:
PROPPATCH "subresponses" indicates either complete failure or success
REPORT responses are handled by SOGo
Therefore it would be nice to refactor those things a little bit and maybe put
some code from SOGo up into SOPE.
-- wsourdeau@inverse.ca, Tue, 22 Apr 2008 15:21:32 -0400
ACL:
- the "default user" concept in the SOGo ACL paradigm should probably match
the "authenticated" role in SOGo/SOPE. Also, we should reconsider the handling
of the DAV:authenticated principal wrt the DAV ACL interface.
- we should add support for DAV privilege descriptions
-- wsourdeau@inverse.ca, Tue, 29 Apr 2008 12:05:17 -0400

View file

@ -10,7 +10,7 @@ import sogoLogin
# must be kept in sync with SoObjects/SOGo/SOGoDefaults.plist
# this should probably be fetched magically...
SOGoSupportedLanguages = [ "Arabic", "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English", "Finnish",
SOGoSupportedLanguages = [ "Arabic", "Basque", "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English", "Finnish",
"SpanishSpain", "SpanishArgentina", "French", "German",
"Icelandic", "Italian", "Hungarian", "BrazilianPortuguese",
"NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak",

View file

@ -46,7 +46,7 @@ class preferencesTest(unittest.TestCase):
def testPreventInvitationsWhiteList(self):
"""Add to the PreventInvitations Whitelist"""
self.prefs.set("whiteList", white_listed_attendee)
self.prefs.set("whiteList", simplejson.dumps(white_listed_attendee))
whitelist = self.prefs.get_settings('Calendar')['PreventInvitationsWhitelist']
self.assertEqual(whitelist, white_listed_attendee)

View file

@ -56,7 +56,7 @@ class preventInvitationsTest(unittest.TestCase):
""" Set PreventInvitation add to WhiteList and accept the Invitation"""
#- First, add the Organiser to the Attendee's whitelist
self.prefs.set('enablePreventInvitations', '0')
self.prefs.set("whiteList", white_listed_attendee)
self.prefs.set("whiteList", simplejson.dumps(white_listed_attendee))
whitelist = self.prefs.get_settings('Calendar')['PreventInvitationsWhitelist']
self.assertEqual(whitelist, white_listed_attendee)

View file

@ -0,0 +1,15 @@
/* this file is in UTF-8 format! */
"Help" = "Laguntza";
"Close" = "Itxi";
"Modules" = "Moduluak";
/* Modules short names */
"ACLs" = "ACL-ak";
/* Modules titles */
"ACLs_title" = "Erabiltzaileen karpeten ACL-en kudeaketa";
/* Modules descriptions */
"ACLs_description" = "<p>\"Access Control List\" administrazio moduluak erabiltzaile bakoitzaren egutegi eta helbide liburuen ACL-ak aldatzea baimentzen du.</p><p>Erabiltzaile baten karpetaren ACL-ak aldatzeko idatzi erabiltzailearen izena leihoaren gainaldeko bilaketa eremuan eta klik bikoitza egin gogoko karpetan.</p>";

View file

@ -6,7 +6,7 @@ BUNDLE_NAME = AdministrationUI
AdministrationUI_PRINCIPAL_CLASS = AdministrationUIProduct
AdministrationUI_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
AdministrationUI_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
AdministrationUI_OBJC_FILES = \
AdministrationUIProduct.m \

View file

@ -0,0 +1,118 @@
/* this file is in UTF-8 format! */
/* toolbars */
"Save" = "Gorde";
"Close" = "Itxi";
"Edit User Rights" = "Erabiltzailearen baimenak aldatu";
"Home" = "Hasiera";
"Calendar" = "Egutegia";
"Address Book" = "Helbide liburua";
"Mail" = "Emaila";
"Preferences" = "Hoberespenak";
"Administration" = "Administrazio";
"Disconnect" = "Deskonektatu";
"Right Administration" = "Baimenen kudeaketa";
"Log Console (dev.)" = "Erregistro kontsola (garap.)";
"User" = "Erabiltzailea";
"Vacation message is enabled" = "\"Oporretan nago\" mezua gaituta dago";
"Help" = "Laguntza";
"noJavascriptError" = "SOGo-k javascript beharrezkoa du. Mesedez ziurtatu zure nabigatzailearen aukeratan aktibatua dagoela.";
"noJavascriptRetry" = "Berriz saiatu";
"Owner:" = "Jabea:";
"Publish the Free/Busy information" = "Argitaratu Libre/Lanpetu informazioa";
"Add..." = "Gehitu...";
"Remove" = "Ezabatu";
"Subscribe User" = "Erabiltzailea harpidetu";
"Any Authenticated User" = "Autentifikatutako edozein erabiltzaile";
"Public Access" = "Atzipen publikoa";
"Any user not listed above" = "Goian zerrendatu gabeko edozein erabiltzaile";
"Anybody accessing this resource from the public area" = "Eremu publikotik baliabidea atzitzen duen edonork";
"Sorry, the user rights can not be configured for that object." = "Barkatu, erabiltzailearen baimenak ezin dira objetu horretarako konfiguratu.";
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
= "Sistema honetan kontua daukan edonor zure \"%{0}\" postontzia atzitzeko gai izango da. Ziur zaude hori nahi duzula? ";
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
= "Sistema honetan kontua daukan edonor zure \"%{0}\" egutegia atzitzeko gai izango da. Ziur zaude hori nahi duzula? ";
"Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
= "Internet-eko edonor zure \"%{0}\" egutegia atzitzeko gai izango da, naiz eta sistema honetan konturik ez eduki. Informazio hau egokia da internet publikorako?";
"Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?"
= "Sistemako edozein erabiltzaile zure \"%{0}\" helbide liburua atzitzeko gai izango da. Ziur zaude hori nahi duzula?";
"Potentially anyone on the Internet will be able to access your address book \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
= "Internet-eko edonor zure \"%{0}\" helbide liburua atzitzeko gai izango da, naiz eta sistema honetan konturik ez eduki. Informazio hau egokia da internet publikorako?";
"Give Access" = "Baimendu atzipena";
"Keep Private" = "Pribatua mantendu";
/* generic.js */
"Unable to subscribe to that folder!"
= "Ezin da karpeta hori harpidetu!";
"You cannot subscribe to a folder that you own!"
= "Ezin duzu zure karpeta bat harpidetu!";
"Unable to unsubscribe from that folder!"
= "Ezin da karpetaren harpidetza kendu!";
"You cannot unsubscribe from a folder that you own!"
= "Ezin duzu zure karpeta baten harpidetza kendu!";
"Unable to rename that folder!" = "Karpetaren izena ezin da aldatu!";
"You have already subscribed to that folder!"
= "Karpeta hau dagoeneko harpidetuta daukazu!";
"The user rights cannot be edited for this object!"
= "Objetu honen erabiltzaile baimenak ezin dira editatu!";
"A folder by that name already exists." = "Izen hori daukan karpeta existitzen da dagoeneko.";
"You cannot create a list in a shared address book."
= "Ezin duzu zerrenda bat sortu partekatutako helbide liburu batean";
"Warning" = "Oharra";
"Can't contact server" = "Errore gertatu da zerbitzariarekin konektatzerakoan. Mesedez saiatu beranduago.";
"You are not allowed to access this module or this system. Please contact your system administrator."
= "Ez daukazu modulu edo sistema honetarako atzipen baimenik. Mesedez, jarri harremanetan sistemaren administratzailearekin.";
"You don't have the required privileges to perform the operation."
= "Ez daukazu eragiketa egiteko beharrezko baimenik.";
"noEmailForDelegation" = "Zure gonbidapena delegatu nahi duzun email helbidea zehaztu behar duzu.";
"delegate is organizer" = "Delegatua antolatzailea da. Mesedez, aukeratu beste delegatu bat.";
"delegate is a participant" = "DElegatua parte-hartzailea da jada.";
"delegate is a group" = "Zehaztutako helbidea talde bati dagokio. Pertsona baten gain bakarrik delega dezakezu.";
"Snooze for " = "Errepikatu ";
"5 minutes" = "5 minutu";
"10 minutes" = "10 minutu";
"15 minutes" = "15 minutu";
"30 minutes" = "30 minutu";
"45 minutes" = "45 minutu";
"1 hour" = "1 ordu";
"1 day" = "1 egun";
/* common buttons */
"OK" = "Onartu";
"Cancel" = "Ezeztatu";
"Yes" = "Bai";
"No" = "Ez";
/* alarms */
"Reminder:" = "Ohartarazpena:";
"Start:" = "Hasi:";
"Due Date:" = "Epemuga:";
"Location:" = "Kokapen";
/* mail labels */
"Important" = "Garrantzitsua";
"Work" = "Lana";
"Personal" = "Pertsonala";
"To Do" = "Egitekoa";
"Later" = "Beranduago";
"a2_Sunday" = "Ig";
"a2_Monday" = "Al";
"a2_Tuesday" = "As";
"a2_Wednesday" = "Az";
"a2_Thursday" = "Os";
"a2_Friday" = "Or";
"a2_Saturday" = "Lr";

View file

@ -94,7 +94,7 @@
"OK" = "OK";
"Cancel" = "Cancelar";
"Yes" = "Sim";
"No" = "No";
"No" = "Não";
/* alarms */
"Reminder:" = "Lembrete:";
@ -109,10 +109,10 @@
"To Do" = "Tarefa";
"Later" = "Adiar";
"a2_Sunday" = "Do";
"a2_Monday" = "Se";
"a2_Tuesday" = "Te";
"a2_Wednesday" = "Qu";
"a2_Thursday" = "Qu";
"a2_Friday" = "Se";
"a2_Saturday" = "Sa";
"a2_Sunday" = "Dom";
"a2_Monday" = "Seg";
"a2_Tuesday" = "Ter";
"a2_Wednesday" = "Qua";
"a2_Thursday" = "Qui";
"a2_Friday" = "Sex";
"a2_Saturday" = "Sab";

View file

@ -1,7 +1,7 @@
/* this file is in UTF-8 format! */
/* toolbars */
"Save" = "Sauver";
"Save" = "Enregistrer";
"Close" = "Fermer";
"Edit User Rights" = "Édition des droits";

View file

@ -6,7 +6,7 @@ BUNDLE_NAME = CommonUI
CommonUI_PRINCIPAL_CLASS = CommonUIProduct
CommonUI_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
CommonUI_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
CommonUI_OBJC_FILES += \
CommonUIProduct.m \

View file

@ -0,0 +1,215 @@
/* this file is in UTF-8 format! */
"Contact" = "Kontaktua";
"Address" = "Helbidea";
"Photos" = "Argazkiak";
"Other" = "Bestelakoak";
"Address Books" = "Helbide Liburuak";
"Addressbook" = "helbideliburua";
"Addresses" = "Helbideak";
"Update" = "Eguneratu";
"Cancel" = "Ezeztatu";
"Common" = "Arrunta";
"Contact editor" = "Kontaktuen editorea";
"Contact viewer" = "Kontaktuen ikuskatzailea";
"Email" = "Emaila";
"Screen Name" = "Pantailaren izena";
"Extended" = "Luzatua";
"Fax" = "Fax";
"Firstname" = "Izena";
"Home" = "Hasiera";
"HomePhone" = "EtxekoTelefonoa";
"Lastname" = "Abizena";
"Location" = "Kokapena";
"MobilePhone" = "Telefono mugikorra";
"Name" = "Izena";
"OfficePhone" = "BulegokoTelefonoa";
"Organization" = "Erakundea";
"Work Phone" = "Laneko telefonoa";
"Phone" = "Telefonoa";
"Phones" = "Telefonoak";
"Postal" = "Posta";
"Save" = "Gorde";
"Internet" = "Internet";
"Unit" = "Unitatea";
"delete" = "ezabatu";
"edit" = "aldatu";
"invalidemailwarn" = "Idatzitako posta elektronikoa baliogabea da";
"new" = "berria";
"Preferred Phone" = "Hobetsitako telefonoa";
"Move To" = "Mugitu hona";
"Copy To" = "Kopiatu hona";
"Add to:" = "Gehitu hona:";
/* Tooltips */
"Create a new address book card" = "Sortu helbide liburu txartel berria";
"Create a new list" = "Sortu zerrenda berria";
"Edit the selected card" = "Aldatu aukeratutako txartela";
"Send a mail message" = "Bidali mezua";
"Delete selected card or address book" = "Ezabatu hautatutako txartela edo helbide liburua";
"Reload all contacts" = "Kontaktu guztiak birkargatu";
"htmlMailFormat_UNKNOWN" = "Ezezaguna";
"htmlMailFormat_FALSE" = "Testu hutsa";
"htmlMailFormat_TRUE" = "HTML";
"Name or Email" = "Izena edo email helbidea";
"Category" = "Kategoria";
"Personal Addressbook" = "Helbide-liburu pertsonala";
"Search in Addressbook" = "Bilatu Helbide-liburuan";
"New Card" = "Txartel berria";
"New List" = "Zerrenda berria";
"Edit" = "Aldatu";
"Properties" = "Ezaugarriak";
"Sharing..." = "Partekatzen...";
"Write" = "Idatzi";
"Delete" = "Ezabatu";
"Instant Message" = "Berehalako mezua";
"Add..." = "Gehitu...";
"Remove" = "Ezabatu";
"Please wait..." = "Mesedez itxaron...";
"No possible subscription" = "Ez dago harpidetzarako aukerarik";
"Preferred" = "Hobetsitakoa";
"Display:" = "Bistaratzea:";
"Display Name:" = "Erakusteko izena:";
"Email:" = "Emaila:";
"Additional Email:" = "Beste emaila:";
"Phone Number:" = "Telefono zenbakia";
"Prefers to receive messages formatted as:" = "Nahiago du mezuak honako formatuan jasotzea:";
"Screen Name:" = "Pantailaren izena";
"Categories:" = "Kategoriak:";
"First:" = "Lehenengoa:";
"Last:" = "Azkena:";
"Nickname:" = "Goitizena:";
"Telephone" = "Telefonoa:";
"Work:" = "Lana:";
"Home:" = "Etxea:";
"Fax:" = "Fax-a:";
"Mobile:" = "Mugikorra:";
"Pager:" = "Orrikatzailea:";
/* categories */
"contacts_category_labels" = "Lankide, Lehiakide, Bezero, Lagun, Familia, Negoziokidea, Hornitzailea, Prentsa, VIP";
"Categories" = "Kategoriak";
"New category" = "Kategoria berria";
/* adresses */
"Title:" = "Izenburua";
"Service:" = "Zerbitzua:";
"Company:" = "Enpresa";
"Department:" = "Saila";
"Organization:" = "Saila:";
"Address:" = "Helbidea";
"City:" = "Herria";
"State_Province:" = "Estatua / Probintzia";
"ZIP_Postal Code:" = "Posta kodea";
"Country:" = "Herrialdea";
"Web Page:" = "Web orria";
"Work" = "Lana";
"Other Infos" = "Bestelako informazioak";
"Note:" = "Ohar:";
"Timezone:" = "Ordu-zona:";
"Birthday:" = "Jaiotze data:";
"Birthday (yyyy-mm-dd):" = "Jaiotze data (uuuu-hh-ee):";
"Freebusy URL:" = "LibreLanpetu URL-a:";
"Add as..." = "Gehitu honela...";
"Recipient" = "Jasotzailea";
"Carbon Copy" = "Kopia";
"Blind Carbon Copy" = "Ezkutuko kopia";
"New Addressbook..." = "Helbideliburu berria";
"Subscribe to an Addressbook..." = "Harpidetu helbide liburu bat...";
"Remove the selected Addressbook" = "Ezabatu aukeratutako helbide-liburua";
"Name of the Address Book" = "Helbide-liburuaren izena";
"Are you sure you want to delete the selected address book?"
= "Ziur zaude aukeratutako helbide-lburua ezabatu nahi duzula?";
"You cannot remove nor unsubscribe from a public addressbook."
= "Helbide-liburu publiko bat ezin duzu ezabatu edo harpidetza kendu.";
"You cannot remove nor unsubscribe from your personal addressbook."
= "Ezin duzu ezabatu edo harpidetza kendu zure helbide-liburu pertsonala.";
"Are you sure you want to delete the selected contacts?"
= "Ziur zaude aukeratutako kontaktuak ezabatu nahi dituzula?";
"You cannot delete the card of \"%{0}\"."
= "Ezin duzu \"%{0}\"-en txartela ezabatu.";
"You cannot subscribe to a folder that you own!"
= "Ezin duzu zure karpeta bat harpidetu.";
"Unable to subscribe to that folder!"
= "Ezin da karpeta hori harpidetu.";
/* acls */
"Access rights to" = "Atzipen baimenak honi";
"For user" = "Erabiltzailearentzat";
"Any Authenticated User" = "Autentifikatutako edozein erabiltzaile";
"Public Access" = "Atzipen publikoa";
"This person can add cards to this addressbook."
= "Pertsona honek txartelak gehitu ditzake helbide liburu honetan.";
"This person can edit the cards of this addressbook."
= "Pertsona honek helbide liburu honetako txartelak aldatu ditzake.";
"This person can list the content of this addressbook."
= "Pertsona honek helbide-liburu honetako edukiak zerrendatu ditzake.";
"This person can read the cards of this addressbook."
= "Pertsona honek helbide-liburu honetako txartelak irakurri ditzake.";
"This person can erase cards from this addressbook."
= "Pertsona honek helbide-liburu honetako txartelak ezabatu ditzake.";
"The selected contact has no email address."
= "Aukeratutako kontaktuak ez dauka email helbiderik.";
"Please select a contact." = "Mesedez, aukeratu kontaktu bat.";
/* Error messages for move and copy */
"SoAccessDeniedException" = "Ezin duzu helbide liburu honetan idatzi.";
"Forbidden" = "Ezin duzu helbide liburu honetan idatzi.";
"Invalid Contact" = "Aukeratutako kontaktua jada ez da existitzen.";
"Unknown Destination Folder" = "Aukeratutako helburu helbide-liburua jada ez da existitzen.";
/* Lists */
"List details" = "Zerrendaren xehetasunak";
"List name:" = "Zerrendaren izena:";
"List nickname:" = "Zerrendaren goitizena:";
"List description:" = "Zerrendaren deskribapena:";
"Members" = "Kideak";
"Contacts" = "Kontaktuak";
"Add" = "Gehitu";
"Lists can't be moved or copied." = "Zerrendak ezin dira kopiatu edo mugitu.";
"Export" = "Esportatu";
"Export Address Book..." = "Esportatu helbide liburua...";
"View Raw Source" = "Ikusi Raw iturburua";
"Import Cards" = "Inportatu txartelak";
"Select a vCard or LDIF file." = "Aukeratu vCard edo LDIF fitxategia";
"Upload" = "Kargatu";
"Uploading" = "Kargatzen";
"Done" = "Eginda";
"An error occured while importing contacts." = "Errorea gertatu da txartelak inportatzean.";
"No card was imported." = "Ez da txartelik inportatu.";
"A total of %{0} cards were imported in the addressbook." = "Guztira %{0} txartel inportatu dira helbide liburuan.";
"Reload" = "Birkargatu";
/* Properties window */
"Address Book Name:" = "Helbide-Liburuaren izena:";
"Links to this Address Book" = "Helbide liburu honetarako estekak";
"Authenticated User Access" = "Autentifikatutako erabiltzaileentzako atzipena";
"CardDAV URL: " = "CardDAV URL-a:";

View file

@ -1,20 +1,20 @@
/* this file is in UTF-8 format! */
"Contact" = "Contact";
"Address" = "Address";
"Photos" = "Photos";
"Other" = "Other";
"Contact" = "Contato";
"Address" = "Catálogo";
"Photos" = "Fotos";
"Other" = "Outros";
"Address Books" = "Addressbooks";
"Address Books" = "Catálogo de Endereços";
"Addressbook" = "Catálogo";
"Addresses" = "Contato";
"Addresses" = "Endereços";
"Update" = "Atualizar";
"Cancel" = "Cancelar";
"Common" = "Comum";
"Contact editor" = "Editor de Contatos";
"Contact viewer" = "Visualizador de Contatos";
"Email" = "Email";
"Screen Name" = "Nome Apresentação";
"Screen Name" = "Nome de Exibição";
"Extended" = "Extendido";
"Fax" = "Fax";
"Firstname" = "Primeiro Nome";
@ -32,16 +32,16 @@
"Postal" = "CEP";
"Save" = "Salvar";
"Internet" = "Internet";
"Unit" = "Setor";
"Unit" = "Unidade";
"delete" = "apagar";
"edit" = "editar";
"invalidemailwarn" = "O email informado é inválido";
"new" = "novo";
"Preferred Phone" = "Telefone Preferencial";
"Move To" = "Move To";
"Copy To" = "Copy To";
"Add to:" = "Add to:";
"Move To" = "Mover para";
"Copy To" = "Copiar para";
"Add to:" = "Adicionar em:";
/* Tooltips */
@ -50,14 +50,14 @@
"Edit the selected card" = "Edita o contato selecionado";
"Send a mail message" = "Envia uma mensagem de email";
"Delete selected card or address book" = "Apaga o contato ou catálogo selecionado";
"Reload all contacts" = "Reload all contacts";
"Reload all contacts" = "Recarregar todos os contatos";
"htmlMailFormat_UNKNOWN" = "Desconhecido";
"htmlMailFormat_FALSE" = "Texto Puro";
"htmlMailFormat_TRUE" = "HTML";
"Name or Email" = "Nome ou Email";
"Category" = "Category";
"Category" = "Categoria";
"Personal Addressbook" = "Catálogo Pessoal";
"Search in Addressbook" = "Localizar no Catálogo";
@ -76,15 +76,15 @@
"No possible subscription" = "Sem possibilidades de inscrição";
"Preferred" = "Preferido";
"Display:" = "Display:";
"Display:" = "Exibição:";
"Display Name:" = "Exibir Nome:";
"Email:" = "Endereço de Email:";
"Additional Email:" = "Additional Email:";
"Additional Email:" = "Email Adicional:";
"Phone Number:" = "Phone Number:";
"Prefers to receive messages formatted as:" = "Prefers to receive messages formatted as:";
"Screen Name:" = "Screen Name:";
"Categories:" = "Categories:";
"Phone Number:" = "Telefone:";
"Prefers to receive messages formatted as:" = "Prefere receber mensagens formatadas como:";
"Screen Name:" = "Nome de Exibição:";
"Categories:" = "Categorias:";
"First:" = "Primeiro Nome:";
"Last:" = "Último Nome:";
@ -98,22 +98,22 @@
"Pager:" = "Pager:";
/* categories */
"contacts_category_labels" = "Colleague, Competitor, Customer, Friend, Family, Business Partner, Provider, Press, VIP";
"Categories" = "Categories";
"New category" = "New category";
"contacts_category_labels" = "Colega, Concorrente, Cliente, Amigo, Família, Parceiro de Negócios, Provedor, Press, VIP";
"Categories" = "Categorias";
"New category" = "Nova categoria";
/* adresses */
"Title:" = "Título:";
"Service:" = "Serviço:";
"Company:" = "Empresa:";
"Department:" = "Department:";
"Organization:" = "Organization:";
"Department:" = "Departamento";
"Organization:" = "Organização";
"Address:" = "Endereço:";
"City:" = "Cidade:";
"State_Province:" = "Estado:";
"ZIP_Postal Code:" = "CEP:";
"Country:" = "País:";
"Web Page:" = "Web Page:";
"Web Page:" = "Página Web:";
"Work" = "Comercial";
"Other Infos" = "Outras Informações";
@ -125,7 +125,7 @@
"Freebusy URL:" = "URL Livre/Ocupado:";
"Add as..." = "Adicionar como...";
"Recipient" = "Recipient";
"Recipient" = "Destinatário";
"Carbon Copy" = "Cópia Carbono";
"Blind Carbon Copy" = "Cópia Carbono Oculta";
@ -158,8 +158,8 @@
"Access rights to" = "Direitos de acesso para";
"For user" = "Para usuário";
"Any Authenticated User" = "Any Authenticated User";
"Public Access" = "Public Access";
"Any Authenticated User" = "Qualquer Usuário Autenticado";
"Public Access" = "Acesso Público";
"This person can add cards to this addressbook."
= "Essa pessoa pode adicionar contatos ao meu catálogo.";
@ -185,25 +185,25 @@
"Unknown Destination Folder" = "O catálogo de destino selecionado não existe.";
/* Lists */
"List details" = "List details";
"List name:" = "List name:";
"List nickname:" = "List nickname:";
"List description:" = "List description:";
"Members" = "Members";
"Contacts" = "Contacts";
"Add" = "Add";
"Lists can't be moved or copied." = "Lists can't be moved or copied.";
"Export" = "Export";
"Export Address Book..." = "Export Address Book...";
"List details" = "Detalhes da lista";
"List name:" = "Lista nome:";
"List nickname:" = "Lista Apelido:";
"List description:" = "Lista descrição:";
"Members" = "Membros";
"Contacts" = "Contatos";
"Add" = "Adicionar";
"Lists can't be moved or copied." = "As listas não podem ser movidos ou copiados.";
"Export" = "Exportar";
"Export Address Book..." = "Exportar Catálogo de Endereço...";
"View Raw Source" = "Visualizar Fonte";
"Import Cards" = "Import Cards";
"Select a vCard or LDIF file." = "Select a vCard or LDIF file.";
"Upload" = "Upload";
"Import Cards" = "Importar cartões";
"Select a vCard or LDIF file." = "Selecione um arquivo vCard ou LDIF.";
"Upload" = "Carregar";
"Uploading" = "Carregando";
"Done" = "Done";
"An error occured while importing contacts." = "An error occured while importing contacts.";
"No card was imported." = "No card was imported.";
"A total of %{0} cards were imported in the addressbook." = "A total of %{0} cards were imported in the addressbook.";
"Done" = "Pronto";
"An error occured while importing contacts." = "Ocorreu um erro ao importar contatos.";
"No card was imported." = "Nenhum cartão foi importado.";
"A total of %{0} cards were imported in the addressbook." = "Um total de %{0} cartões foram importados no catálogo de endereços.";
"Reload" = "Atualizar";

View file

@ -6,7 +6,7 @@ BUNDLE_NAME = ContactsUI
ContactsUI_PRINCIPAL_CLASS = ContactsUIProduct
ContactsUI_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
ContactsUI_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
ContactsUI_OBJC_FILES = \
UIxContactsUserFolders.m \

View file

@ -0,0 +1,48 @@
ACCEPTED = "onartua";
COMPLETED = "amaitua";
DECLINED = "gaitzetsia";
DELEGATED = "delegatua";
"IN-PROCESS" = "prozesuan";
"NEEDS-ACTION" = "ekintza behar du";
TENTATIVE = "behin-behineko";
organized_by_you = "zuk antolatua";
you_are_an_attendee = "Partaidea zera";
add_info_text = "SOGo-k ez du iMIP 'ADD' eskaerarik onartzen";
publish_info_text = "Bidaltzaileak atxikitutako ekitaldiari buruz jakinarazten zaitu.";
cancel_info_text = "Zure gonbidapena edo ekitaldi osoa bertan behera utzi da.";
request_info_no_attendee = "partaideei topaketa bat proposatzen die. Email hau jakinarazpen bezala jasotzen duzu, ez zaude partaide bezala programatua";
Appointment = "Hitzordua";
"Status Update" = "Egoera eguneraketa";
was = "zen";
Organizer = "Antolatzailea";
Time = "Ordua";
Attendees = "Partaideak";
request_info = "bileran parte-hartzera gonbidatzen zaitu.";
"Add to calendar" = "Egutegira gehitu";
"Delete from calendar" = "Egutegitik ezabatu";
"Update status" = "Egoera eguneratu";
Accept = "Onartu";
Decline = "Uko egin";
Tentative = "Behin-behineko";
"Delegate ..." = "Delegatu ...";
"Delegated to" = "Beste honen esku utzia";
"Update status in calendar" = "Egoera egunerartu egutegian";
"delegated from" = "Beste honek zure esku utzia";
reply_info_no_attendee = "Ekitaldi planifikazio bati erantzuna jaso duzu baina erantzunaren bidaltzailea ez da parte-hartzailea.";
reply_info = "Zuk egindako gonbidapen bati erantzuna da hau.";
"to" = "nori";
"Untitled" = "Izenburu-gabea";
"Size" = "Tamaina";
"Digital signature is not valid" = "Sinadura digitala ez da baliozkoa";
"Message is signed" = "Mezua sinatua dago";
"Subject" = "Gaia";
"From" = "Nork";
"Date" = "Data";
"To" = "Nori";
"Issuer" = "jaulkitzailea";

View file

@ -10,7 +10,7 @@ you_are_an_attendee = "você é um participante";
add_info_text = "As solicitações iMIP 'ADD' ainda não são suportadas pelo SOGo.";
publish_info_text = "O solicitante lhe informa sobre um evento anexo.";
cancel_info_text = "Seu convite ou evento foi cancelado.";
request_info_no_attendee = "está propondo um reunião aos participantes. Você está recebendo este email como uma notificação, você não está agendado como um particiopante.";
request_info_no_attendee = "está propondo uma reunião aos participantes. Você está recebendo este email como uma notificação, você não está agendado como um particiopante.";
Appointment = "Apontamento";
"Status Update" = "Status da Atualização";
was = "foi";

View file

@ -6,7 +6,7 @@ BUNDLE_NAME = MailPartViewers
MailPartViewers_PRINCIPAL_CLASS = MailPartViewersProduct
MailPartViewers_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
MailPartViewers_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
MailPartViewers_OBJC_FILES += \
MailPartViewersProduct.m \

View file

@ -0,0 +1,308 @@
/* this file is in UTF-8 format! */
/* Icon's label */
"Create" = "Sortu";
"Empty Trash" = "Hustu zakarrontzia";
"Delete" = "Ezabatu";
"Expunge" = "Suntsitu";
"Forward" = "Birbidali";
"Get Mail" = "Eskuratu mezuak";
"Junk" = "Zaborra";
"Reply" = "Erantzun";
"Reply All" = "Erantzun denei";
"Print" = "Inprimatu";
"Stop" = "Gelditu";
"Write" = "Idatzi";
"Search" = "Bilatu";
"Send" = "Bidali";
"Contacts" = "Kontaktuak";
"Attach" = "Erantsi";
"Save" = "Gorde";
"Options" = "Aukerak";
"Close" = "Itxi";
"Size" = "Tamaina";
/* Tooltips */
"Send this message now" = "Bidali mezu hau orain";
"Select a recipient from an Address Book" = "Aukeratu jasotzailea Helbide-liburu batetik";
"Include an attachment" = "Erantsi eranskin bat";
"Save this message" = "Gorde mezu hau";
"Get new messages" = "Eskuratu mezu berriak";
"Create a new message" = "Sortu mezu berria";
"Go to address book" = "Joan helbide liburura";
"Reply to the message" = "Erantzun mezuari";
"Reply to sender and all recipients" = "Erantzun bidaltzaile eta jasotzaile guztiei";
"Forward selected message" = "Birbidali aukeratutako mezua";
"Delete selected message or folder" = "Ezabatu aukeratutako mezu edo karpeta";
"Mark the selected messages as junk" = "Markatu aukeratutako mezua zabor-posta gisa";
"Print this message" = "Inprimatu mezu hau";
"Stop the current transfer" = "Gelditu uneko transferentzia";
"Attachment" = "Eranskina";
"Unread" = "Irakurri-gabea";
"Flagged" = "Bandera dauka";
"Search multiple mailboxes" = "Bilatu postontzi anitzetan";
/* Main Frame */
"Home" = "Hasiera";
"Calendar" = "Egutegia";
"Addressbook" = "Helbide liburua";
"Mail" = "Emaila";
"Right Administration" = "Eskubideen kudeaketa";
"Help" = "Laguntza";
/* Mail account main windows */
"Welcome to the SOGo Mailer. Use the folder tree on the left to browse your mail accounts!" = "Ongi etorria SOGo webmail-era. Erabili ezkerreko zuhaitza zure email kontuak arakatzeko ";
"Read messages" = "Irakurri mezuak";
"Write a new message" = "Idatzi mezu berria";
"Share: " = "Partekatu:";
"Account: " = "Kontua:";
"Shared Account: " = "Partekatutako kontua:";
/* acls */
"Access rights to" = "Atzipen baimenak honi";
"For user" = "Erabiltzailearentzat";
"Any Authenticated User" = "Autentifikatutako edozein erabiltzaile";
"List and see this folder" = "Zerrendatu eta ikuskatu karpeta hau";
"Read mails from this folder" = "Irakurri karpeta honetako mezuak";
"Mark mails read and unread" = "Markatu mezuak irakurrita eta irakurri gabeko gisa";
"Modify the flags of the mails in this folder" = "Karpeta honetako mezuen banderak aldatu.";
"Insert, copy and move mails into this folder" = "Txertatu, kopiatu eta mugitu mezuak karpeta honetara";
"Post mails" = "Bidali emailak";
"Add subfolders to this folder" = "Sortu azpikarpetak karpeta honetan";
"Remove this folder" = "Ezabatu karpeta hau";
"Erase mails from this folder" = "Ezabatu karpeta honetako mezuak";
"Expunge this folder" = "Suntsitu karpeta honetako mezuak";
"Export This Folder" = "Esportatu karpeta hau";
"Modify the acl of this folder" = "Karpeta honen ACL-ak aldatu";
"Saved Messages.zip" = "Gorde Messages.zip";
"Update" = "Eguneratu";
"Cancel" = "Ezeztatu";
/* Mail edition */
"From" = "Nork";
"Subject" = "Gaia";
"To" = "Nori";
"Cc" = "Kopia";
"Bcc" = "Izkutuko kopia";
"Reply-To" = "Erantzun-honi";
"Add address" = "Gehitu helbidea";
"Body" = "Gorputza";
"Open" = "Ireki";
"Select All" = "Denak aukeratu";
"Attach Web Page..." = "Erantsi Web Orria ...";
"file" = "fitxategia";
"files" = "fitxategiak";
"Save all" = "Dena gorde";
"to" = "Nori";
"cc" = "Kopia";
"bcc" = "Izkutuko kopia";
"Edit Draft..." = "Aldatu zirriborroa...";
"Load Images" = "Kargatu irudiak";
"Return Receipt" = "Jasotze agiria";
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "Mezu honen bidaltzaileak mezua irakurtzen duzunean jakinarazia izan nahi du. Jakinarazpena bidali nahi diozu?";
"Return Receipt (displayed) - %@"= "Jasotze agiria (bistaratua) - %@";
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "Honako hau zuk %@-ri bidalitako mezuaren jasotze-agiria da.\n\nOharra: Jasotze agiri honek mezua jasotzailearen ordenagailuan bistaratu dela bakarrik ziurtatzen du. Ezin da ziurtatu jasotzaileak mezuaren edukia irakurri edota ulertu duenik.";
"Priority" = "Lehentasuna";
"highest" = "Altuena";
"high" = "Altua";
"normal" = "Arrunta";
"low" = "Baxua";
"lowest" = "Baxuena";
"This mail is being sent from an unsecure network!" = "Mezu hau sare ez-seguru bat erabiliz hari zara bidaltzen!";
"Address Book:" = "Helbide Liburua";
"Search For:" = "Bilatu hau:";
/* Popup "show" */
"all" = "denak";
"read" = "irakurria";
"unread" = "irakurri-gabea";
"deleted" = "ezabatua";
"flagged" = "bandera dauka";
/* MailListView */
"Sender" = "Bidaltzailea";
"Subject or Sender" = "Gaia edo Bidaltzailea";
"To or Cc" = "Nori edo kopia";
"Entire Message" = "Mezu osoa";
"Date" = "Data";
"View" = "Ikuskatu";
"All" = "Denak";
"No message" = "Mezurik ez";
"messages" = "mezuak";
"first" = "Lehenengoa";
"previous" = "Aurrekoa";
"next" = "Hurrengoa";
"last" = "Azkena";
"msgnumber_to" = "nori";
"msgnumber_of" = "nork";
"Mark Unread" = "Markatu irakurri-gabeko gisa";
"Mark Read" = "Markatu irakurri gisa";
"Untitled" = "Izenburu gabe";
/* Tree */
"SentFolderName" = "Bidalia";
"TrashFolderName" = "Zakarrontzia";
"InboxFolderName" = "Sarrera";
"DraftsFolderName" = "Zirriborroak";
"SieveFolderName" = "Iragazkiak";
"Folders" = "Karpetak"; /* title line */
/* MailMoveToPopUp */
"MoveTo" = "Mugitu &hellip;";
/* Address Popup menu */
"Add to Address Book..." = "Gehitu helbide liburuan...";
"Compose Mail To" = "Idatzi mezua honi";
"Create Filter From Message..." = "Sortu iragazkia mezua erabiliz...";
/* Image Popup menu */
"Save Image" = "Gorde mezua";
"Save Attachment" = "Gorde eranskina";
/* Mailbox popup menus */
"Open in New Mail Window" = "Ireki \"mezu berri\" leihoan";
"Copy Folder Location" = "Kopiatu karpetaren kokapena";
"Subscribe..." = "Harpidetu...";
"Mark Folder Read" = "Markatu karpeta irakurri gisa";
"New Folder..." = "karpeta berria";
"Compact This Folder" = "Trinkotu karpeta hau";
"Search Messages..." = "Bilatu mezuak...";
"Sharing..." = "Partekatzea....";
"New Subfolder..." = "Azpikarpeta berria...";
"Rename Folder..." = "Karpeta berrizendatu...";
"Delete Folder" = "Ezabatu karpeta";
"Use This Folder For" = "Erabili karpeta hau ";
"Get Messages for Account" = "Eskuratu kontu honen mezuak";
"Properties..." = "Ezaugarriak...";
"Delegation..." = "Ordezkaritza ...";
/* Use This Folder menu */
"Sent Messages" = "Bidalitako mezuak";
"Drafts" = "Zirriborroak";
"Deleted Messages" = "Ezabatutako mezuak";
/* Message list popup menu */
"Open Message In New Window" = "Ireki mezua leiho berrian";
"Reply to Sender Only" = "Erantzun bidaltzaileari soilik";
"Reply to All" = "Erantzun denei";
"Edit As New..." = "Editatu mezu berri bezala...";
"Move To" = "Mugitu hona";
"Copy To" = "Kopiatu hona";
"Label" = "Etiketa";
"Mark" = "Markatu";
"Save As..." = "Gorde honela...";
"Print Preview" = "Inprimatzeko aurrebista";
"View Message Source" = "Ikusi mezuaren iturburua";
"Print..." = "Inprimatu...";
"Delete Message" = "Ezabatu mezua";
"Delete Selected Messages" = "Ezabatu aukeratutako mezuak";
"This Folder" = "Karpeta hau";
/* Label popup menu */
"None" = "Bat ere ez";
/* Mark popup menu */
"As Read" = "Irakurri gisa";
"Thread As Read" = "Haria irakurri gisa";
"As Read By Date..." = "Data bidez irakurritako gisa...";
"All Read" = "Denak irakurrita";
"Flag" = "Bandera";
"As Junk" = "Zabor-posta gisa";
"As Not Junk" = "ez zaborra gisa";
"Run Junk Mail Controls" = "Exekutatu zabor-posta kontrolak";
"Search messages in:" = "Bilatu mezuak hemen:";
"Search" = "Bilatu";
"Search subfolders" = "Bilatu azpikarpetak";
"Match any of the following" = "Irizpide hauetako edozein betetzen dituztenak";
"Match all of the following" = "Irizpide guzti hauek betetzen dituztenak";
"contains" = "dauka";
"does not contain" = "ez dauka";
"No matches found" = "Ez da emaitzarik aurkitu";
"results found" = "emaitza topatu dira";
"result found" = "emaitza topatu da";
"Please specify at least one filter" = "Mesedez, zehaztu gutxienez iragazki bat";
/* Folder operations */
"Name :" = "Izena:";
"Enter the new name of your folder :"
= "Idatzi zure karpetaren izen berria:";
"Do you really want to move this folder into the trash ?"
= "Ziur zaude karpeta hau zakarrontzira mugitu nahi duzula?";
"Operation failed" = "Eragiketak huts egin du";
"Quota" = "Kuota";
"quotasFormat" = "%{0}% erabilia %{1}-n MB ";
"Please select a message." = "Mesedez, aukeratu mezu bat.";
"Please select a message to print." = "Mesedez, aukeratu inprimatzeko mezu bat.";
"Please select only one message to print." = "Mesdez, aukeratu inprimatzekom mezu bakarra.";
"The message you have selected doesn't exist anymore." = "Aukertutako mezua jada ez da existitzen";
"The folder with name \"%{0}\" could not be created."
= "\"%{0}\" izeneko karpeta ezin izan da sortu";
"This folder could not be renamed to \"%{0}\"."
= "Karpeta hau ezin izan da \"%{0}\"-ra berrizendatu.";
"The folder could not be deleted."
= "Karpeta ezin izan da ezabatu.";
"The trash could not be emptied."
= "Zakarrontzia ezin izan da hustu.";
"The folder functionality could not be changed."
= "Karpetaren funtzionalitatea ezin izan da aldatu.";
"You need to choose a non-virtual folder!" = "Karpeta ez-birtual bat aukeratu behar duzu!";
"Moving a message into its own folder is impossible!"
= "Mezu bat bere karpeta berera ezin da mugitu!";
"Copying a message into its own folder is impossible!"
= "Mezu bat ezin da bere karpetara kopiatu!";
/* Message operations */
"The messages could not be moved to the trash folder. Would you like to delete them immediately?"
= "Mezuak ezin izan dira zakarrontzira mugitu. Berehala ezabatu nahi dituzu?";
/* Message editing */
"error_missingsubject" = "Mezuak ez dauka gairik. Ziur zaude horrela bidali nahi duzula?";
"error_missingrecipients" = "Mesedez, zehaztu gutxienez jasotzaile bat.";
"Send Anyway" = "Bidali hala ere";
"Error while saving the draft:" = "Errorea zirriborroa gordetzerakoan:";
"Error while uploading the file \"%{0}\":" = "Errorea \"%{0}\" fitxategia igotzerakoan:";
"There is an active file upload. Closing the window will interrupt it." = "Fitxategi igoera aktibo bat dago. Leihoa ixteak etengo du.";
/* Message sending */
"cannot send message: (smtp) all recipients discarded" = "Ezin izan da mezua bidali: jasotzaile guztiak baliogabeak dira.";
"cannot send message (smtp) - recipients discarded:" = "Ezin izan da mezua bidali. Ondorengo jasotzaileak ez dira baliozkoak:";
"cannot send message: (smtp) error when connecting" = "Ezin izan da mezua bidali: errorea SMTP zerbitzarira konektatzean.";
/* Contacts list in mail editor */
"Email" = "Emaila";
"Name" = "Izena";

View file

@ -26,7 +26,7 @@
/* Tooltips */
"Send this message now" = "Envia esta mensagem agora";
"Select a recipient from an Address Book" = "Seleciona um destinatário de a partir de um Catálogo";
"Select a recipient from an Address Book" = "Seleciona um destinatário de catálogo de endereços";
"Include an attachment" = "Inclui um anexo";
"Save this message" = "Salva esta mensagem";
"Get new messages" = "Receber novas mensagens";
@ -95,7 +95,7 @@
"Subject" = "Assunto";
"To" = "Para";
"Cc" = "Cc";
"Bcc" = "Bcc";
"Bcc" = "Cco";
"Reply-To" = "Responder-Para";
"Add address" = "Adicionar endereço";
"Body" = "Corpo";
@ -109,7 +109,7 @@
"to" = "Para";
"cc" = "Cc";
"bcc" = "Bcc";
"bcc" = "Cco";
"Edit Draft..." = "Editar Rascunho...";
"Load Images" = "Carregar Imagens";
@ -180,7 +180,7 @@
/* Address Popup menu */
"Add to Address Book..." = "Adicionar ao Catálogo...";
"Compose Mail To" = "Escrever Mensagem Parana";
"Compose Mail To" = "Escrever Mensagem Para";
"Create Filter From Message..." = "Criar Filtro Da Mensagem...";
/* Image Popup menu */
@ -261,7 +261,7 @@
"Operation failed" = "Falha na Operação";
"Quota" = "Quota:";
"quotasFormat" = "%{0}% usedo em %{1} MB";
"quotasFormat" = "%{0}% usado em %{1} MB";
"Please select a message." = "Por favor, selecione uma mensagem.";
"Please select a message to print." = "Por favor, selecione a mensagem para imprimir.";

View file

@ -6,7 +6,7 @@ BUNDLE_NAME = MailerUI
MailerUI_PRINCIPAL_CLASS = MailerUIProduct
MailerUI_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
MailerUI_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
MailerUI_OBJC_FILES += \
MailerUIProduct.m \

View file

@ -17,7 +17,7 @@
"Send" = "Send";
"Contacts" = "Kontakter";
"Attach" = "Vedlegg ved";
"Attach" = "Vedlegg";
"Save" = "Lagre";
"Options" = "Innstillinger";
"Close" = "Lukk";

View file

@ -163,7 +163,7 @@
co = [self clientObject];
us = [[context activeUser] userSettings];
if (!(moduleSettings = [us objectForKey: @"Mail"]))
[us setObject:[NSMutableDictionary dictionnary] forKey: @"Mail"];
[us setObject:[NSMutableDictionary dictionary] forKey: @"Mail"];
if (isCollapsing)
{

View file

@ -20,6 +20,7 @@
"Language:" = "اللغة:";
"choose" = "إختار ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -0,0 +1,35 @@
/* English */
{
NSLanguageName = "Basque";
NSFormalName = "Euskara";
NSLocaleCode = "eu"; /* ISO 639-1 */
NSLanguageCode = "eus"; /* ISO 639-2 */
NSParentContext = "";
NSAMPMDesignation = (AM, PM);
NSCurrencySymbol = " €";
NSDateFormatString = "%A, %B %e, %Y";
NSDateTimeOrdering = YMDH;
NSDecimalDigits = ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
NSDecimalSeparator = ",";
NSEarlierTimeDesignations = ("aurreko", "azken", "joan den", "duela");
NSHourNameDesignations = ((0, gauerdia), (10, goiza), (12, eguerdia), (14, arratsaldea), (19, gaua));
NSInternationalCurrencyString = EUR; /* ISO 4217 */
NSLaterTimeDesignations = ("hurrengo", "ondorengo", "datorren");
NSMonthNameArray = (Urtarrila, Otsaila, Martxoa, Apirila, Maiatza, Ekaina, Uztaila, Abuztua, Iraila, Urria, Azaroa, Abendua);
NSNextDayDesignations = (bihar);
NSNextNextDayDesignations = ("hurrengo eguna");
NSPriorDayDesignations = (atzo);
NSShortDateFormatString = "%y/%m/%e";
NSShortMonthNameArray = (Urt, Ots, Mar, Apr, Mai, Eka, Uzt, Abu, Ira, Urr, Aza, Abe);
NSShortTimeDateFormatString = "%/%m/%e %I:%M %p";
NSShortWeekDayNameArray = (Ig, Al, As, Az, Os, Or, Ig);
NSThisDayDesignations = (gaur);
NSThousandsSeparator = ".";
NSTimeDateFormatString = "%A, %B %e, %Y %I:%M:%S %p %Z";
NSTimeFormatString = "%I:%M:%S %p";
NSWeekDayNameArray = (Igandea, Astelehena, Asteartea, Asteazkena, Osteguna, Ostirala, Larunbata);
NSYearMonthWeekDesignations = (urtea, hilabetea, astea);
NSPositiveCurrencyFormatString = "9.999,00$";
NSNegativeCurrencyFormatString = "-9.999,00$";
}

View file

@ -0,0 +1,78 @@
/* this file is in UTF-8 format! */
"title" = "SOGo";
"Username:" = "Erabiltzailea:";
"Password:" = "Pasahitza:";
"Domain:" = "Domeinua";
"Remember username" = "Gogoratu erabiltzaile-izena";
"Connect" = "Konektatu";
"Wrong username or password." = "Erabiltzaile edo pasahitz okerrak";
"cookiesNotEnabled" = "Ezin zara sartu zure arakatzailearen 'cookie'-ak desgaituta daudelako. Mesedez, gaitu 'cookie'-ak zure arakatzailearen ezarpenetan.";
"browserNotCompatible" = "Zure arakatzailearen bertsioa ez da onartzen webgune honetan. Gure gomendioa Firefox erabiltzea da. Klikatu ondorengo estekan arakatzaile honen bertsio berriena jeisteko.";
"alternativeBrowsers" = "Aukeran, honako beste arakatzaileak erabili ditzakezu";
"alternativeBrowserSafari" = "Aukeran, Safari arakatzailea erabili dezakezu ere.";
"Download" = "Deskargatu";
"Language:" = "Hizkuntza";
"choose" = "Aukeratu ...";
"Arabic" = "العربية";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";
"Dutch" = "Nederlands";
"English" = "English";
"Finnish" = "Suomi";
"French" = "Français";
"German" = "Deutsch";
"Hungarian" = "Magyar";
"Icelandic" = "Íslenska";
"Italian" = "Italiano";
"NorwegianBokmal" = "Norsk bokmål";
"NorwegianNynorsk" = "Norsk nynorsk";
"Polish" = "Polski";
"BrazilianPortuguese" = "Português brasileiro";
"Russian" = "Русский";
"Slovak" = "Slovensky";
"SpanishSpain" = "Español (España)";
"SpanishArgentina" = "Español (Argentina)";
"Swedish" = "Svenska";
"Ukrainian" = "Українська";
"Welsh" = "Cymraeg";
"About" = "Honi buruz";
"AboutBox" = "Inverse-k garatua. SOGo ezaugarri guztidun groupware zerbitzaria da, eskalagarritasunean eta simpletasunean bideratzen dena.<br/><br/>\nSOGo-k AJAX-ean oinarritutako web interfaze aberatsa eskeintzen du eta jatorrizko bezero anitz onartzen ditu ValDAv eta CardDAV bezalako protokolo estandarrak erabiliz. <br/><br/>\nSOGo <a href=\"http://gnu.org/licenses/gpl.html\">GNU GPL</a> 2. bertsio edo berriago lizentziapean dago banatua, eta honen zatiak GNU LGPL 2. bertsio lizentziapean. Software librea da: Askatasun osoa daukazu aldatu eta banatzeko. EZ dago inolako GARANTIARIK, legeak onartzen duen neurrian.<br/><br/>\nLaguntza aukera ezberdinak ikusteko klikatu <a href=\"http://www.sogo.nu/en/support/community.html\">hemen</a> ";
"Your account was locked due to too many failed attempts." = "Zure kontua blokeatuta dago saiakera oker gehiegi egiteagatik.";
"Your account was locked due to an expired password." = "Zure kontua blokeatuta dago pasahitza iraungita dagoelako.";
"Login failed due to unhandled error case: " = "Login-ak hutsegin du landu gabeko akats-kasu batengatik:";
"Change your Password" = "Aldatu zure pasahitza";
"The password was changed successfully." = "Pasahitza ondo aldatu da.";
"Your password has expired, please enter a new one below:" = "Zure pasahitza iraungita dago, mesedez sartu pasahitz berria:";
"Password must not be empty." = "Pasahitza ezin da hutsa izan.";
"The passwords do not match. Please try again." = "Pasahaitzak ez datoz bat. Mesedez, saiatu berriz.";
"Password Grace Period" = "Pasahitzaren graziazko aldia";
"You have %{0} logins remaining before your account is locked. Please change your password in the preference dialog." = "%{0} saiakera geratzen zaizkizu zure kontua blokeatu aurretik. Mesedez, aldatu pasahitza hoberespenen elkarrizketa-koadroan.";
"Password about to expire" = "Pasahitza iraungitzear dago";
"Your password is going to expire in %{0} %{1}." = "Zure pasahitza %{0} %{1}-n iraungiko da.";
"days" = "egun";
"hours" = "ordu";
"minutes" = "minutu";
"seconds" = "segundu";
"Password change failed" = "Pasahitz aldaketak hutsegin du";
"Password change failed - Permission denied" = "Pasahitz aldaketak hutsegin du - Baimena ukatua";
"Password change failed - Insufficient password quality" = "Pasahitz aldaketak hutsegin du - Pasahitzaren kalitate eskasa";
"Password change failed - Password is too short" = "Pasahitz aldaketak hutsegin du - Pasahitz motzegia";
"Password change failed - Password is too young" = "Pasahitz aldaketak hutsegin du - Pasahitza berriegia da";
"Password change failed - Password is in history" = "Pasahitz aldaketak hutsegin du - Pasahitza historikoan dago";
"Unhandled policy error: %{0}" = "Landu gabeko politika errorea: %{0}";
"Unhandled error response" = "Landu gabeko errore erantzuna";
"Password change is not supported." = "Pasahitz aldaketa ez dago onartua.";
"Unhandled HTTP error code: %{0}" = "Landu gabeko HTTP errore kodea: %{0}";
"New password:" = "Pasahitz berria";
"Confirmation:" = "Berrespena:";
"Cancel" = "Ezeztatu";
"Please wait..." = "Itxaron mesedez...";

View file

@ -10,7 +10,7 @@
"Connect" = "Conectar";
"Wrong username or password." = "Usuário ou Senha Inválido.";
"cookiesNotEnabled" = "Você não pode logar por a opção cookies está desabilitada. Por favor, habilite os cookies nas configurações de seu navegador e tente novamente.";
"cookiesNotEnabled" = "Você não pode logar porque a opção cookies está desabilitada. Por favor, habilite os cookies nas configurações de seu navegador e tente novamente.";
"browserNotCompatible" = "Foi detectado que a atual versão de seu navegador não é suportado neste site. Recomentamos que use o Firefox. Clique no link abaixo para baixar a versão atual deste navegador.";
"alternativeBrowsers" = "Alternativamente, você pode usar os seguinte navegadores compatíveis";
@ -20,6 +20,7 @@
"Language:" = "Idioma:";
"choose" = "Escolha ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";
@ -44,7 +45,7 @@
"Welsh" = "Cymraeg";
"About" = "Sobre";
"AboutBox" = "Developed by Inverse, SOGo is a fully-featured groupware server with a focus on scalability and simplicity.<br/><br/>⏎ \nSOGo provides a rich AJAX-based Web interface and supports multiple native clients through the use of standard protocols such as CalDAV and CardDAV.<br/><br/>⏎ \nSOGo is distributed under the <a href=\"http://gnu.org/licenses/gpl.html\">GNU GPL</a> version 2 or later and parts are distributed under the GNU LGPL version 2. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.<br/><br/>⏎ \nSee <a href=\"http://www.sogo.nu/en/support/community.html\">this page</a> for various support options.";
"AboutBox" = "Desenvolvido por Inverse, Sogo é um servidor de groupware cheio de recursos com foco em escalabilidade e simplicidade.\nSogo fornece uma interface Web baseada em AJAX ricos e suporta vários clientes nativos através da utilização de protocolos padrão como CalDAV e CardDAV.\nSogo é distribuído sob a GNU GPL <a href=\"http://gnu.org/licenses/gpl.html\"> </a> versão 2 ou posterior e as partes são distribuídos sob a GNU LGPL versão 2. Este é um software livre: você é livre para mudar e redistribuí-lo. Não há NENHUMA GARANTIA, até o limite permitido por lei.\nVeja <a href=\"http://www.sogo.nu/en/support/community.html\"> desta página</a> para várias opções de suporte.";
"Your account was locked due to too many failed attempts." = "Sua conta foi bloqueada devido a muitas tentativas fracassadas.";
"Your account was locked due to an expired password." = "Sua conta foi bloqueada devido a uma senha expirada.";
@ -67,7 +68,7 @@
"Password change failed - Insufficient password quality" = "Alteração da senha falhou - Senha muito fraca";
"Password change failed - Password is too short" = "Alteração da senha falhou - Senha muito curta";
"Password change failed - Password is too young" = "Alteração da senha falhou - Senha usada recentemente";
"Password change failed - Password is in history" = "Password is too young - Senha está no histórico";
"Password change failed - Password is in history" = "Alteração de senha falhou - Password está no histórico";
"Unhandled policy error: %{0}" = "Política de erro não tratada: %{0}";
"Unhandled error response" = "Erro de resposta não tratado";
"Password change is not supported." = "Alteração da senha não suportada.";

View file

@ -20,6 +20,7 @@
"Language:" = "Llengua:";
"choose" = "Triar ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Jazyk:";
"choose" = "Vybrat ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Sprog:";
"choose" = "Vælg ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Taal:";
"choose" = "Kies...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Language:";
"choose" = "Choose ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Kieli:";
"choose" = "Valitse ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Langue:";
"choose" = "Choisir ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -6,7 +6,7 @@ BUNDLE_NAME = MainUI
MainUI_PRINCIPAL_CLASS = MainUIProduct
MainUI_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
MainUI_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
MainUI_OBJC_FILES += \
MainUIProduct.m \

View file

@ -20,6 +20,7 @@
"Language:" = "Sprache:";
"choose" = "Auswählen ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Nyelv:";
"choose" = "Válasszon ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -19,6 +19,7 @@
"Language:" = "Tungumál:";
"choose" = "Velja...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Lingua:";
"choose" = "Scegli...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Språk:";
"choose" = "Velg ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Språk:";
"choose" = "Velg ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Język:";
"choose" = "Wybierz ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Язык:";
"choose" = "Выбрать ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -52,7 +52,9 @@
#import <SBJson/NSObject+SBJSON.h>
#define intervalSeconds 900 /* 15 minutes */
#define INTERVALSECONDS 900 /* 15 minutes */
#define PADDING 8
#define HALFPADDING PADDING/2
@interface SOGoUserHomePage : UIxComponent
@ -151,23 +153,23 @@
startInterval = 0;
else
startInterval = ([currentDate timeIntervalSinceDate: startDate]
/ intervalSeconds);
/ INTERVALSECONDS);
delta = [[currentDate timeZoneDetail] timeZoneSecondsFromGMT] - [[startDate timeZoneDetail] timeZoneSecondsFromGMT];
startInterval += (delta/60/15);
startInterval = (startInterval < -4 ? -4 : startInterval);
startInterval += (delta/INTERVALSECONDS);
startInterval = (startInterval < -(HALFPADDING) ? -(HALFPADDING) : startInterval);
currentDate = [record objectForKey: @"endDate"];
if ([currentDate earlierDate: endDate] == endDate)
endInterval = itemCount - 1;
else
endInterval = ([currentDate timeIntervalSinceDate: startDate]
/ intervalSeconds);
/ INTERVALSECONDS);
delta = [[currentDate timeZoneDetail] timeZoneSecondsFromGMT] - [[startDate timeZoneDetail] timeZoneSecondsFromGMT];
endInterval += (delta/60/15);
endInterval += (delta/INTERVALSECONDS);
endInterval = (endInterval < 0 ? 0 : endInterval);
endInterval = (endInterval > itemCount+4 ? itemCount+4 : endInterval);
endInterval = (endInterval > itemCount+HALFPADDING ? itemCount+HALFPADDING : endInterval);
// Update bit string representation
// If the user is a resource with restristed amount of bookings, keep the sum of overlapping events
@ -230,19 +232,19 @@
// Slices of 15 minutes. The +8 is to take into account that we can
// have a timezone change during the freebusy lookup. We have +4 at the
// beginning and +4 at the end.
intervals = interval / intervalSeconds + 8;
intervals = interval / INTERVALSECONDS + PADDING;
// Build a bit string representation of the freebusy data for the period
freeBusyItems = calloc(intervals, sizeof (unsigned int));
[self _fillFreeBusyItems: (freeBusyItems+4)
count: (intervals-4)
[self _fillFreeBusyItems: (freeBusyItems+HALFPADDING)
count: (intervals-PADDING)
withRecords: [fb fetchFreeBusyInfosFrom: start to: end forContact: uid]
fromStartDate: startDate
toEndDate: endDate];
// Convert bit string to a NSArray. We also skip by the default the non-requested information.
freeBusy = [NSMutableArray arrayWithCapacity: intervals];
for (count = 4; count < (intervals-4); count++)
for (count = HALFPADDING; count < (intervals-HALFPADDING); count++)
{
[freeBusy addObject: [NSString stringWithFormat: @"%d", *(freeBusyItems + count)]];
}

View file

@ -20,6 +20,7 @@
"Language:" = "Idioma:";
"choose" = "Elija ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Idioma:";
"choose" = "Elija ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -19,6 +19,7 @@
"Language:" = "Språk:";
"choose" = "Välj ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

View file

@ -20,6 +20,7 @@
"Language:" = "Мова:";
"choose" = "Вибрати ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
"Catalan" = "Català";
"Czech" = "Česky";
"Danish" = "Dansk (Danmark)";

Some files were not shown because too many files have changed in this diff Show more