diff --git a/ActiveSync/NSString+ActiveSync.h b/ActiveSync/NSString+ActiveSync.h
index 4aad558a2..963b3d00a 100644
--- a/ActiveSync/NSString+ActiveSync.h
+++ b/ActiveSync/NSString+ActiveSync.h
@@ -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
diff --git a/ActiveSync/NSString+ActiveSync.m b/ActiveSync/NSString+ActiveSync.m
index 6aa054d10..a66f38252 100644
--- a/ActiveSync/NSString+ActiveSync.m
+++ b/ActiveSync/NSString+ActiveSync.m
@@ -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.
diff --git a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
index cdd4cd9d1..9c306061a 100644
--- a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
+++ b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
@@ -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"];
diff --git a/ActiveSync/SOGoActiveSyncDispatcher.m b/ActiveSync/SOGoActiveSyncDispatcher.m
index fd3de3108..e2e301565 100644
--- a/ActiveSync/SOGoActiveSyncDispatcher.m
+++ b/ActiveSync/SOGoActiveSyncDispatcher.m
@@ -917,6 +917,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 +1002,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 +1025,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"];
}
@@ -2630,7 +2633,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"];
diff --git a/ActiveSync/SOGoMailObject+ActiveSync.m b/ActiveSync/SOGoMailObject+ActiveSync.m
index 45c865c84..15e3b1ca7 100644
--- a/ActiveSync/SOGoMailObject+ActiveSync.m
+++ b/ActiveSync/SOGoMailObject+ActiveSync.m
@@ -224,6 +224,18 @@ struct GlobalObjectId {
while ((key = [e nextObject]))
{
+ // Don't use body parts from nested bodies if not of type multipart/alternative. - e.g. body of type message/rfc822
+ // Use only parts of level 0 or 1.
+ if ([key countOccurrencesOfString: @"."] > 1)
+ continue;
+ else if ([key countOccurrencesOfString: @"."] == 1)
+ {
+ // Ignore nested parts if the container is not of type multipart/alternative.
+ part = [self lookupInfoForBodyPart: [[key componentsSeparatedByString: @"."] objectAtIndex:0]];
+ if (!([[part valueForKey: @"type"] isEqualToString: @"multipart"] && [[part valueForKey: @"subtype"] isEqualToString: @"alternative"]))
+ continue;
+ }
+
part = [self lookupInfoForBodyPart: key];
type = [part valueForKey: @"type"];
subtype = [part valueForKey: @"subtype"];
@@ -596,7 +608,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 +623,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;
}
diff --git a/NEWS b/NEWS
index 4bc7d920a..55f030370 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,52 @@
-2.2.17a-zentyal1 (2014-04-15)
---------------------
+2.2.19 (2015-05-XX)
+------
-Zentyal Release
+New features
+ - Internet headers are now shown in Outlook
-2.2.17a (2014-03-15)
+Enhancements
+ - Sharing request among different Outlook versions
+ - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails
+ - 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
+ - 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)
+ - 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.18 (2015-04-XX)
+-------------------
+
+Enhancements
+ - improved multipart handling using EAS
+ - added systemd startup script (PR#76)
+ - updated Brazilian (Portuguese), Dutch, Norwegian (Bokmal), Polish, Russian, and Spanish (Spain) translations
+
+Bug fixes
+ - 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
+
+2.2.17a (2015-03-15)
--------------------
Bug fixes
@@ -62,42 +105,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)
-------------------
diff --git a/Scripts/sogo-systemd-redhat b/Scripts/sogo-systemd-redhat
new file mode 100644
index 000000000..7fdd56b96
--- /dev/null
+++ b/Scripts/sogo-systemd-redhat
@@ -0,0 +1,12 @@
+[Unit]
+Description=SOGo is a groupware server
+After=network.target
+
+[Service]
+Type=forking
+ExecStart=/usr/sbin/sogod -WOWorkersCount 3 -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
diff --git a/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings b/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
index f6117f8ef..5fcb33090 100644
--- a/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
+++ b/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
@@ -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."
diff --git a/SoObjects/Appointments/MSExchangeFreeBusySOAPRequest.m b/SoObjects/Appointments/MSExchangeFreeBusySOAPRequest.m
index 01c9e8aea..425178b36 100644
--- a/SoObjects/Appointments/MSExchangeFreeBusySOAPRequest.m
+++ b/SoObjects/Appointments/MSExchangeFreeBusySOAPRequest.m
@@ -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
diff --git a/SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings b/SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
index 8923eae93..9b2176e92 100644
--- a/SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
+++ b/SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
@@ -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";
diff --git a/UI/Common/BrazilianPortuguese.lproj/Localizable.strings b/UI/Common/BrazilianPortuguese.lproj/Localizable.strings
index dabc4b454..0e6c1db6e 100644
--- a/UI/Common/BrazilianPortuguese.lproj/Localizable.strings
+++ b/UI/Common/BrazilianPortuguese.lproj/Localizable.strings
@@ -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";
diff --git a/UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings b/UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
index 934456c1c..4a09eae65 100644
--- a/UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
+++ b/UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
@@ -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";
diff --git a/UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings b/UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
index d038b316d..94b9e6bec 100644
--- a/UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
+++ b/UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
@@ -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";
diff --git a/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings b/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
index b07718473..92af97fe0 100644
--- a/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
+++ b/UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
@@ -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.";
diff --git a/UI/MailerUI/NorwegianBokmal.lproj/Localizable.strings b/UI/MailerUI/NorwegianBokmal.lproj/Localizable.strings
index c389d4c13..e2f6937d9 100644
--- a/UI/MailerUI/NorwegianBokmal.lproj/Localizable.strings
+++ b/UI/MailerUI/NorwegianBokmal.lproj/Localizable.strings
@@ -17,7 +17,7 @@
"Send" = "Send";
"Contacts" = "Kontakter";
-"Attach" = "Vedlegg ved";
+"Attach" = "Vedlegg";
"Save" = "Lagre";
"Options" = "Innstillinger";
"Close" = "Lukk";
diff --git a/UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings b/UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
index 4bc1a21ca..0f8f74599 100644
--- a/UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
+++ b/UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
@@ -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";
@@ -44,7 +44,7 @@
"Welsh" = "Cymraeg";
"About" = "Sobre";
-"AboutBox" = "Developed by Inverse, SOGo is a fully-featured groupware server with a focus on scalability and simplicity.
⏎ \nSOGo provides a rich AJAX-based Web interface and supports multiple native clients through the use of standard protocols such as CalDAV and CardDAV.
⏎ \nSOGo is distributed under the GNU GPL 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.
⏎ \nSee this page 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 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 desta página 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 +67,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.";
diff --git a/UI/MainUI/SOGoUserHomePage.m b/UI/MainUI/SOGoUserHomePage.m
index c6223e656..42f373f8d 100644
--- a/UI/MainUI/SOGoUserHomePage.m
+++ b/UI/MainUI/SOGoUserHomePage.m
@@ -52,7 +52,9 @@
#import
-#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)]];
}
diff --git a/UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings b/UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
index 01dc12d01..77db2492b 100644
--- a/UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
+++ b/UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
@@ -23,12 +23,13 @@
/* vacation (auto-reply) */
"Enable vacation auto reply" = "Habilitar auto resposta de férias";
-"Auto reply message :" = "AutoResponder somente uma vez a cada remetente com o seguinte texto :";
+"Auto reply message :" = "Auto Responder somente uma vez a cada remetente com o seguinte texto:";
"Email addresses (separated by commas) :" = "Endereço de e-mail (separado por vírgulas):";
"Add default email addresses" = "Adicionar endereço de e-mail padrão";
"Days between responses :" = "Dias entre respostas:";
"Do not send responses to mailing lists" = "Não envie respostas para lista de e-mails";
"Disable auto reply on" = "Desativar resposta automática em";
+"Always send vacation message response" = "Sempre enviar resposta de mensagem de férias";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Favor especificar a sua mensagem e seus endereços de e-mail para o qual você deseja ativar resposta automática.";
"Your vacation message must not end with a single dot on a line." = "Sua mensagem de férias não deve terminar com um ponto único em uma linha.";
@@ -40,9 +41,12 @@
"Keep a copy" = "Manter uma cópia";
"Please specify an address to which you want to forward your messages."
= "Favor especificar um endereço para o qual você deseja encaminhar suas mensagens.";
+"You are not allowed to forward your messages to an external email address." = "Você não tem permissão para transmitir a sua mensagem para um endereço de e-mail externo.";
+"You are not allowed to forward your messages to an internal email address." = "Você não tem permissão para transmitir a sua mensagem para um endereço de e-mail interno.";
+
/* d & t */
-"Current Time Zone :" = "Fuso Horário :";
+"Current Time Zone :" = "Fuso Horário:";
"Short Date Format :" = "Formato da Data (Curto) :";
"Long Date Format :" = "Formato da Data (Longo) :";
"Time Format :" = "Formato da Hora :";
@@ -170,7 +174,7 @@
"User Name:" = "Nome do Usuário:";
"Password:" = "Senha:";
-"Full Name:" = "Nome Compelto:";
+"Full Name:" = "Nome Completo:";
"Email:" = "E-mail:";
"Reply To Email:" = "Responder para o Email:";
"Signature:" = "Assinatura:";
@@ -207,7 +211,7 @@
"Mail" = "Correio";
"Last" = "Último usado";
"Default Module :" = "Módulo Padrão:";
-"SOGo Version :" = "Versão SOGo:";
+"SOGo Version :" = "Versão do SOGo:";
"Language :" = "Idioma :";
"choose" = "Escolha ...";
@@ -283,7 +287,7 @@
"Header" = "Cabeçalho";
"Body" = "Corpo";
"Flag the message with:" = "Marcar a mensagem com:";
-"Discard the message" = "Discate a mensagem";
+"Discard the message" = "Descarte a mensagem";
"File the message in:" = "Arquivo da mensagem em:";
"Keep the message" = "Manter a mensagem";
"Forward the message to:" = "Encaminhar a mensagem para:";
@@ -293,7 +297,7 @@
"is under" = "abaixo";
"is over" = "acima";
-"is" = "is";
+"is" = "é igual";
"is not" = "não é";
"contains" = "contem";
"does not contain" = "não contem";
@@ -307,19 +311,19 @@
"Answered" = "Respondido";
"Flagged" = "Marcado";
"Junk" = "Lixo";
-"Not Junk" = "Não é Lixo";
+"Not Junk" = "Não é Lixo Eletrônico";
/* Password policy */
"The password was changed successfully." = "Senha alterada com sucesso.";
-"Password must not be empty." = "Le mot de passe ne doit pas être vide.";
-"The passwords do not match. Please try again." = "Les mots de passe ne sont pas identiques. Essayez de nouveau.";
-"Password change failed" = "Échec au changement";
-"Password change failed - Permission denied" = "Échec au changement - mauvaises permissions";
-"Password change failed - Insufficient password quality" = "Échec au changement - qualité insuffisante";
-"Password change failed - Password is too short" = "Échec au changement - mot de passe trop court";
-"Password change failed - Password is too young" = "Échec au changement - mot de passe trop récent";
-"Password change failed - Password is in history" = "Échec au changement - mot de passe dans l'historique";
-"Unhandled policy error: %{0}" = "Erreur inconnue pour le ppolicy: %{0}";
-"Unhandled error response" = "Erreur inconnue";
-"Password change is not supported." = "Changement de mot de passe non-supporté.";
-"Unhandled HTTP error code: %{0}" = "Code HTTP non-géré: %{0}";
+"Password must not be empty." = "A Senha não pode ser vazia.";
+"The passwords do not match. Please try again." = "As senhas não coincidem. Por favor, tente novamente.";
+"Password change failed" = "Alteração de senha falhou";
+"Password change failed - Permission denied" = "Alteração de senha falhou - Permissão Negada";
+"Password change failed - Insufficient password quality" = "Alteração de senha falhou pois não atende os requisitos minímos";
+"Password change failed - Password is too short" = "Alteração de senha falhou - Senha muito curta";
+"Password change failed - Password is too young" = "Alteração de senha falhou - Senha alterada recentemente";
+"Password change failed - Password is in history" = "Alteração de senha falhou - A Senha já foi utilizada";
+"Unhandled policy error: %{0}" = "Erro de política não tratada: %{0}";
+"Unhandled error response" = "Resposta de erro não tratada";
+"Password change is not supported." = "Troca de senha não suportada";
+"Unhandled HTTP error code: %{0}" = "Código de erro HTTP não tratada: %{0}";
diff --git a/UI/PreferencesUI/Dutch.lproj/Localizable.strings b/UI/PreferencesUI/Dutch.lproj/Localizable.strings
index f4fe086f4..89a6ad964 100644
--- a/UI/PreferencesUI/Dutch.lproj/Localizable.strings
+++ b/UI/PreferencesUI/Dutch.lproj/Localizable.strings
@@ -29,6 +29,7 @@
"Days between responses :" = "Dagen tussen reacties:";
"Do not send responses to mailing lists" = "Geen reacties naar maillinglijsten sturen";
"Disable auto reply on" = "Automatisch bericht bij afwezigheid uitschakelen op";
+"Always send vacation message response" = "Afwezigheidsbericht altijd versturen";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Geeft u alstublieft de tekst van het automatische bericht bij afwezigheid op en de e-mailadressen waarvoor het moet worden geactiveerd.";
"Your vacation message must not end with a single dot on a line." = "Uw automatisch bericht bij afwezigheid mag niet eindigen met een enkele punt op een regel.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Kopie bewaren";
"Please specify an address to which you want to forward your messages."
= "Alstublieft het e-mailadres waarnaar u de berichten wilt laten doorsturen aangeven.";
+"You are not allowed to forward your messages to an external email address." = "Email naar een extern emailadres doorsturen is niet toegestaan";
+"You are not allowed to forward your messages to an internal email address." = "Email naar een intern emailadres doorsturen is niet toegestaan";
+
/* d & t */
"Current Time Zone :" = "Huidige tijdzone:";
diff --git a/UI/PreferencesUI/NorwegianBokmal.lproj/Localizable.strings b/UI/PreferencesUI/NorwegianBokmal.lproj/Localizable.strings
index 17be0b3fa..c1f59838d 100644
--- a/UI/PreferencesUI/NorwegianBokmal.lproj/Localizable.strings
+++ b/UI/PreferencesUI/NorwegianBokmal.lproj/Localizable.strings
@@ -12,6 +12,7 @@
"Forward" = "Videresend";
"Password" = "Passord";
"Categories" = "Kategorier";
+"Appointments invitations" = "Avtale varslinger";
"Name" = "Navn";
"Color" = "Farge";
"Add" = "Legg til";
@@ -28,6 +29,7 @@
"Days between responses :" = "Dager mellom svar:";
"Do not send responses to mailing lists" = "Ikke send svar til e-postlister";
"Disable auto reply on" = "Skru av auto-svar";
+"Always send vacation message response" = "Alltid send ferie melding";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Skriv melding og angi din e-postadresse som du vil aktivere auto-svar for.";
"Your vacation message must not end with a single dot on a line." = "Fraværsmeldingen kan ikke slutte med ett ensomt punktum på en linje. ";
@@ -39,6 +41,9 @@
"Keep a copy" = "Behold en kopi";
"Please specify an address to which you want to forward your messages."
= "Angi adressen du vil videresende dine meldinger til.";
+"You are not allowed to forward your messages to an external email address." = "Du har ikke lov til å videresende mail til en ekstern e-mail addresse.";
+"You are not allowed to forward your messages to an internal email address." = "Du har ikke love til å videresende mail til en ekstern e-mail addresse.";
+
/* d & t */
"Current Time Zone :" = "Gjeldende tidssone:";
@@ -137,7 +142,7 @@
"Forward messages:" = "Videresend meldinger:";
"messageforward_inline" = "Innsatt";
-"messageforward_attached" = "Vedlegg";
+"messageforward_attached" = "Som Vedlegg";
"When replying to a message:" = "Ved svar på melding: ";
"replyplacement_above" = "Start svaret ovenfor";
@@ -152,6 +157,9 @@
"displayremoteinlineimages_never" = "Aldri";
"displayremoteinlineimages_always" = "Alltid";
+"Auto save every" = "Lagre automatisk";
+"minutes" = "minutter";
+
/* Contact */
"Personal Address Book" = "Personlig addressebok";
"Collected Address Book" = "Samlet addressebok";
diff --git a/UI/PreferencesUI/Polish.lproj/Localizable.strings b/UI/PreferencesUI/Polish.lproj/Localizable.strings
index 9936e5a4c..e432f9182 100644
--- a/UI/PreferencesUI/Polish.lproj/Localizable.strings
+++ b/UI/PreferencesUI/Polish.lproj/Localizable.strings
@@ -29,6 +29,7 @@
"Days between responses :" = "Dni pomiędzy odpowiedziami :";
"Do not send responses to mailing lists" = "Nie wysyłaj odpowiedzi do grup pocztowych";
"Disable auto reply on" = "Zablokuj autoodpowiedź w";
+"Always send vacation message response" = "Zawsze wysyłaj autoodpowiedź";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Podaj treść wiadomości i twoje adresy e-mail, dla których chcesz włączyć autoodpowiedź.";
"Your vacation message must not end with a single dot on a line." = "Twoja wiadomość nie może kończyć się kropką w pustej linii.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Zatrzymaj kopię";
"Please specify an address to which you want to forward your messages."
= "Podaj adres, na który chcesz przekazywać wiadomości.";
+"You are not allowed to forward your messages to an external email address." = "Nie masz uprawnień do przesyłania dalej swoich wiadomości na zewnętrzny adres e-mail.";
+"You are not allowed to forward your messages to an internal email address." = "Nie masz uprawnień do przesyłania dalej swoich wiadomości na wewnętrzny adres e-mail.";
+
/* d & t */
"Current Time Zone :" = "Bieżąca strefa czasowa :";
diff --git a/UI/PreferencesUI/Russian.lproj/Localizable.strings b/UI/PreferencesUI/Russian.lproj/Localizable.strings
index 0dc61be59..59dc0c09e 100644
--- a/UI/PreferencesUI/Russian.lproj/Localizable.strings
+++ b/UI/PreferencesUI/Russian.lproj/Localizable.strings
@@ -29,6 +29,7 @@
"Days between responses :" = "Дни между ответами :";
"Do not send responses to mailing lists" = "Не отправлять ответы на почтовые списки рассылки";
"Disable auto reply on" = "Запрет автоответа включен";
+"Always send vacation message response" = "Всегда отправлять ответное сообщение об отпуске";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Пожалуйста, укажите Ваше сообщение и адреса электронной почты для которых Вы хотите включить автоматический ответ.";
"Your vacation message must not end with a single dot on a line." = "Ваше сообщение о верменном отсутсвии не должно оканчиваться строкой с одиночной точкой.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Оставлять копию";
"Please specify an address to which you want to forward your messages."
= "Пожалуйста укажите адрес, на который вы хотите переадресовать ваши сообщения.";
+"You are not allowed to forward your messages to an external email address." = "Вы не можете пересылать свои сообщения на внешний адрес электронной почты.";
+"You are not allowed to forward your messages to an internal email address." = "Вы не можете пересылать свои сообщения на внутренний адрес электронной почты.";
+
/* d & t */
"Current Time Zone :" = "Текущая временная зона :";
@@ -153,6 +157,9 @@
"displayremoteinlineimages_never" = "Никогда";
"displayremoteinlineimages_always" = "Всегда";
+"Auto save every" = "Автосохранение каждые";
+"minutes" = "минут";
+
/* Contact */
"Personal Address Book" = "Личная адресная книга";
"Collected Address Book" = "Собранные адреса";
diff --git a/UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings b/UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
index 7a5eb414a..55d72d435 100644
--- a/UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
+++ b/UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
@@ -29,6 +29,7 @@
"Days between responses :" = "Dias entre respuestas :";
"Do not send responses to mailing lists" = "No enviar respuestas a las listas de distribución";
"Disable auto reply on" = "Desactivar respuesta automatica";
+"Always send vacation message response" = "Siempre enviar mensaje de vacaciones";
"Please specify your message and your email addresses for which you want to enable auto reply."
= "Por favor, especificar el mensaje y la dirección de correo para aquellos a los que quiere habilitar la respuesta automática.";
"Your vacation message must not end with a single dot on a line." = "El mensaje de vacaciones no puede finalizarse con un único punto en una linea.";
@@ -40,6 +41,9 @@
"Keep a copy" = "Guardar una copia";
"Please specify an address to which you want to forward your messages."
= "Por favor, especificar una dirección para aquellos mensajes que quiere desviar.";
+"You are not allowed to forward your messages to an external email address." = "No esta autorizado a reenviar sus mensajes a una dirección de correo externa.";
+"You are not allowed to forward your messages to an internal email address." = "No esta autorizado a reenviar sus mensajes a una dirección de correo interna.";
+
/* d & t */
"Current Time Zone :" = "Zona horaria actual :";
diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m
index 6e54bc043..9f55e4166 100644
--- a/UI/PreferencesUI/UIxPreferences.m
+++ b/UI/PreferencesUI/UIxPreferences.m
@@ -640,15 +640,21 @@ static NSArray *reminderValues = nil;
return [userDefaults busyOffHours];
}
-- (NSArray *) whiteList
+- (NSString *) whiteList
{
SOGoUserSettings *us;
NSMutableDictionary *moduleSettings;
- NSArray *whiteList;
+ id whiteList;
us = [user userSettings];
moduleSettings = [us objectForKey: @"Calendar"];
- whiteList = [moduleSettings objectForKey:@"PreventInvitationsWhitelist"];
+ whiteList = [moduleSettings objectForKey: @"PreventInvitationsWhitelist"];
+
+ if (whiteList && [whiteList isKindOfClass: [NSDictionary class]])
+ {
+ whiteList = [whiteList jsonRepresentation];
+ }
+
return whiteList;
}
@@ -659,7 +665,7 @@ static NSArray *reminderValues = nil;
us = [user userSettings];
moduleSettings = [us objectForKey: @"Calendar"];
- [moduleSettings setObject: whiteListString forKey: @"PreventInvitationsWhitelist"];
+ [moduleSettings setObject: [whiteListString objectFromJSONString] forKey: @"PreventInvitationsWhitelist"];
[us synchronize];
}
diff --git a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
index 3c5891e81..b3686c62f 100644
--- a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
+++ b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
@@ -7,7 +7,7 @@
"Edit this event or task" = "Editar este evento ou tarefa";
"Print the current calendar view" = "Imprimir a visualização do calendário atual";
"Delete this event or task" = "Apagar este evento ou tarefa";
-"Go to today" = "Vai para hoje";
+"Go to today" = "Ir para Hoje";
"Switch to day view" = "Visualizar Dia";
"Switch to week view" = "Visualizar Semana";
"Switch to month view" = "Visualizar Mês";
@@ -129,7 +129,7 @@
"Update" = "Atualizar";
"Cancel" = "Cancelar";
"show_rejected_apts" = "Exibir apontamentos rejeitados";
-"hide_rejected_apts" = "Ocultar apontamentos rejeitados";
+"hide_rejected_apts" = "Ocultar compromissos rejeitados";
/* Schedule */
@@ -144,7 +144,7 @@
"decline" = "Declinar";
"more attendees" = "Mais Participantes";
"Hide already accepted and rejected appointments" = "Ocultar apontamentos já aceitos e rejeitados";
-"Show already accepted and rejected appointments" = "Exibir apontamentos já aceitos e rejeitados";
+"Show already accepted and rejected appointments" = "Exibir compromissos já aceitos e rejeitados";
/* Print view */
@@ -163,10 +163,10 @@
/* Appointments */
-"Appointment viewer" = "Visualizador de Apontamentos";
-"Appointment editor" = "Editor de Apontamento";
-"Appointment proposal" = "Apontamento Proposto";
-"Appointment on" = "Apontamento em";
+"Appointment viewer" = "Visualizador de Compromissos";
+"Appointment editor" = "Editor de Compromisso";
+"Appointment proposal" = "Compromisso Proposto";
+"Appointment on" = "Compromisso em";
"Start:" = "Inicio:";
"End:" = "Fim:";
"Due Date:" = "Data:";
@@ -210,7 +210,7 @@
"Private" = "Privado";
/* text used in overviews and tooltips */
"empty title" = "Título Vazio";
-"private appointment" = "Apontamento privado";
+"private appointment" = "Compromisso privado";
"Change..." = "Alterar...";
@@ -331,7 +331,7 @@
"cycle_of" = "de";
"No end date" = "Sem data final";
"Create" = "Criar";
-"appointment(s)" = "apontamento(s)";
+"appointment(s)" = "compromisso(s)";
"Repeat until" = "Repetir até";
"First" = "Primeiro";
@@ -429,7 +429,7 @@ validate_endbeforestart = "A data que você informou ocorre antes da data ini
/* menu */
"New Event..." = "Novo Evento...";
-"New Task..." = "Neva Tarefa...";
+"New Task..." = "Nova Tarefa";
"Edit Selected Event..." = "Editar o Evento Selecionado...";
"Delete Selected Event" = "Apagar o Evento Selecionado";
"Select All" = "Selecionar Tudo";
@@ -471,7 +471,7 @@ validate_endbeforestart = "A data que você informou ocorre antes da data ini
"Work days only" = "Somente dias de trabalho";
"The whole day" = "O dia inteiro";
"Between" = "Entre";
-"and" = "and";
+"and" = "e";
"A time conflict exists with one or more attendees.\nWould you like to keep the current settings anyway?"
= "Existe um conflito de tempo com um ou mais participantes.\nGostaria de manter as configurações atuais?";
diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings
index 321198ea8..4bb62c42b 100644
--- a/UI/Scheduler/English.lproj/Localizable.strings
+++ b/UI/Scheduler/English.lproj/Localizable.strings
@@ -325,9 +325,11 @@
"Week(s)" = "Week(s)";
"On" = "On";
"Month(s)" = "Month(s)";
+/* [Event recurrence editor] Ex: _The_ first Sunday */
"The" = "The";
"Recur on day(s)" = "Recur on day(s)";
"Year(s)" = "Year(s)";
+/* [Event recurrence editor] Ex: Every first Sunday _of_ April */
"cycle_of" = "of";
"No end date" = "No end date";
"Create" = "Create";
@@ -548,7 +550,6 @@ vtodo_class2 = "(Confidential task)";
"EventCopyError" = "The copy failed. Please try to copy to a difference calendar.";
"Please select at least one calendar" = "Please select at least one calendar";
-
"Open Task..." = "Open Task...";
"Mark Completed" = "Mark Completed";
"Delete Task" = "Delete Task";
diff --git a/UI/WebServerResources/JavascriptAPIExtensions.js b/UI/WebServerResources/JavascriptAPIExtensions.js
index 190a8e99b..245078268 100644
--- a/UI/WebServerResources/JavascriptAPIExtensions.js
+++ b/UI/WebServerResources/JavascriptAPIExtensions.js
@@ -119,7 +119,7 @@ Date.prototype.clone = function() {
newDate.setTime(this.getTime());
return newDate;
-}
+};
Date.prototype.deltaDays = function(otherDate) {
var day1 = this.getTime();
@@ -130,8 +130,8 @@ Date.prototype.deltaDays = function(otherDate) {
day1 = tmp;
}
- return Math.floor((day2 - day1) / 86400000);
-}
+ return Math.round((day2 - day1) / 86400000);
+};
Date.prototype.daysUpTo = function(otherDate) {
var days = new Array();
@@ -152,7 +152,7 @@ Date.prototype.daysUpTo = function(otherDate) {
// var day1 = day1Date.getTime();
// var day2 = day2Date.getTime();
- var nbrDays = Math.floor((day2 - day1) / 86400000) + 1;
+ var nbrDays = Math.round((day2 - day1) / 86400000) + 1;
for (var i = 0; i < nbrDays; i++) {
var newDate = new Date();
newDate.setTime(day1 + (i * 86400000));
@@ -217,9 +217,8 @@ Date.prototype.stringWithSeparator = function(separator) {
};
Date.prototype.addDays = function(nbrDays) {
- var milliSeconds = this.getTime();
- milliSeconds += 86400000 * Math.round(nbrDays);
- this.setTime(milliSeconds);
+ var dat = new Date(this.valueOf());
+ this.setDate(dat.getDate() + Math.round(nbrDays));
};
Date.prototype.earlierDate = function(otherDate) {
@@ -249,7 +248,7 @@ Date.prototype.beginOfDay = function() {
beginOfDay.setMilliseconds(0);
return beginOfDay;
-}
+};
Date.prototype.beginOfWeek = function() {
var offset = firstDayOfWeek - this.getDay();
diff --git a/UI/WebServerResources/MailerUI.css b/UI/WebServerResources/MailerUI.css
index abd14f5c8..61c8750b2 100644
--- a/UI/WebServerResources/MailerUI.css
+++ b/UI/WebServerResources/MailerUI.css
@@ -510,7 +510,6 @@ DIV.mailer_htmlcontent P
white-space: normal;
font-family: sans-serif;
font-size: inherit;
- margin: 0px;
padding: 0px;
}
diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js
index 995a11f9c..1941ed32b 100644
--- a/UI/WebServerResources/MailerUI.js
+++ b/UI/WebServerResources/MailerUI.js
@@ -916,10 +916,11 @@ function openMailbox(mailbox, reload) {
dataSource.init(inboxData['uids'], inboxData['threaded'], inboxData['headers'], inboxData['quotas']);
inboxData = null; // invalidate this initial lookup
}
- else
+ else {
// Fetch UIDs and headers from server
var content = Object.toJSON(urlParams);
dataSource.load(content);
+ }
// Cache data source
Mailer.dataSources.set(key, dataSource);
// Update unseen count
diff --git a/UI/WebServerResources/UIxAttendeesEditor.js b/UI/WebServerResources/UIxAttendeesEditor.js
index 7ca8e2874..16d297425 100644
--- a/UI/WebServerResources/UIxAttendeesEditor.js
+++ b/UI/WebServerResources/UIxAttendeesEditor.js
@@ -391,6 +391,12 @@ function redisplayEventSpans() {
etHour++;
}
+ if (isAllDay) {
+ addDays++;
+ stHour = stMinute = 0;
+ etHour = etMinute = 0;
+ }
+
if (stHour < displayStartHour) {
stHour = displayStartHour;
stMinute = 0;
@@ -432,8 +438,10 @@ function redisplayEventSpans() {
if (currentSpanNbr > 3) {
currentSpanNbr = 0;
currentCellNbr++;
- currentCell = row.cells[currentCellNbr];
- spans = $(currentCell).childNodesWithTag("span");
+ if (currentCellNbr < row.cells.length) {
+ currentCell = row.cells[currentCellNbr];
+ spans = $(currentCell).childNodesWithTag("span");
+ }
}
deltaSpans--;
}
@@ -897,7 +905,7 @@ _freeBusyCacheEntry.prototype = {
var adjustedEd = ed.beginOfDay();
var nbrDays = adjustedSd.deltaDays(adjustedEd) + 1;
var offsetEnd = offset + (nbrDays * 96);
- if (Math.round(this.entries.length/96) >= nbrDays) {
+ if (Math.round((this.entries.length - offset)/96) >= nbrDays) {
entries = this.entries.slice(offset, offsetEnd);
}
}
@@ -934,7 +942,6 @@ _freeBusyCacheEntry.prototype = {
// Period extends to after current end
if (start.getTime() <= nextDate.getTime()) {
start = nextDate.beginOfDay();
- start.addDays(1);
}
fetchDates.push({ start: start, end: end });
}
@@ -952,7 +959,7 @@ _freeBusyCacheEntry.prototype = {
if (this.startDate) {
if (start.getTime() < this.startDate) {
days = start.deltaDays(this.startDate);
- if (entries.length == (days * 96)) {
+ if (Math.round(entries.length/96) == days) {
// New period is just before previous period
this.startDate = start;
this.entries = entries.concat(this.entries);
@@ -1123,7 +1130,7 @@ function displayFreeBusyForNode(input) {
var rowIndex = input.parentNode.parentNode.sectionRowIndex;
var row = $("freeBusyData").tBodies[0].rows[rowIndex];
var nodes = row.cells;
- //log ("displayFreeBusyForNode index " + rowIndex + " (" + nodes.length + " cells)");
+ //log ("displayFreeBusyForNode index " + rowIndex + " uid " + input.uid + " (" + nodes.length + " cells)");
if (input.uid) {
if (!input.hasfreebusy) {
// log("forcing draw of nodes");
@@ -1451,10 +1458,11 @@ function onTimeDateWidgetChange() {
function prepareTableHeaders() {
var startTimeDate = $("startTime_date");
var startDate = startTimeDate.inputAsDate();
+ startDate.setHours(0, 0);
var endTimeDate = $("endTime_date");
var endDate = endTimeDate.inputAsDate();
- endDate.setTime(endDate.getTime());
+ endDate.setHours(0, 0);
var rows = $("freeBusyHeader").rows;
var days = startDate.daysUpTo(endDate);
diff --git a/packaging/rhel/sogo.spec b/packaging/rhel/sogo.spec
index 8f275e956..02bf547ce 100644
--- a/packaging/rhel/sogo.spec
+++ b/packaging/rhel/sogo.spec
@@ -14,6 +14,13 @@
%{!?python_sys_pyver: %global python_sys_pyver %(/usr/bin/python -c "import sys; print sys.hexversion")}
+# Systemd for fedora >= 17 or el 7
+%if 0%{?fedora} >= 17 || 0%{?rhel} >= 7
+ %global _with_systemd 1
+%else
+ %global _with_systemd 0
+%endif
+
%define sogo_user sogo
Summary: SOGo
@@ -217,7 +224,13 @@ make DESTDIR=${RPM_BUILD_ROOT} \
GNUSTEP_INSTALLATION_DOMAIN=SYSTEM \
CC="$cc" LDFLAGS="$ldflags" \
install
-install -d ${RPM_BUILD_ROOT}/etc/init.d
+
+%if 0%{?_with_systemd}
+ install -d ${RPM_BUILD_ROOT}/usr/lib/systemd/system/
+%else
+ install -d ${RPM_BUILD_ROOT}/etc/init.d
+%endif
+
install -d ${RPM_BUILD_ROOT}/etc/cron.d
install -d ${RPM_BUILD_ROOT}/etc/cron.daily
install -d ${RPM_BUILD_ROOT}/etc/logrotate.d
@@ -236,8 +249,15 @@ install -m 600 Scripts/sogo.cron ${RPM_BUILD_ROOT}/etc/cron.d/sogo
cp Scripts/tmpwatch ${RPM_BUILD_ROOT}/etc/cron.daily/sogo-tmpwatch
chmod 755 ${RPM_BUILD_ROOT}/etc/cron.daily/sogo-tmpwatch
cp Scripts/logrotate ${RPM_BUILD_ROOT}/etc/logrotate.d/sogo
-cp Scripts/sogo-init.d-redhat ${RPM_BUILD_ROOT}/etc/init.d/sogod
-chmod 755 ${RPM_BUILD_ROOT}/etc/init.d/sogod
+
+%if 0%{?_with_systemd}
+ cp Scripts/sogo-systemd-redhat ${RPM_BUILD_ROOT}/usr/lib/systemd/system/sogod.service
+ chmod 644 ${RPM_BUILD_ROOT}/usr/lib/systemd/system/sogod.service
+%else
+ cp Scripts/sogo-init.d-redhat ${RPM_BUILD_ROOT}/etc/init.d/sogod
+ chmod 755 ${RPM_BUILD_ROOT}/etc/init.d/sogod
+%endif
+
cp Scripts/sogo-default ${RPM_BUILD_ROOT}/etc/sysconfig/sogo
rm -rf ${RPM_BUILD_ROOT}%{_bindir}/test_quick_extract
@@ -365,14 +385,24 @@ fi
%post
# update timestamp on imgs,css,js to let apache know the files changed
find %{_libdir}/GNUstep/SOGo/WebServerResources -exec touch {} \;
-/sbin/chkconfig --add sogod
-/etc/init.d/sogod condrestart >&/dev/null
+%if 0%{?_with_systemd}
+ systemctl enable sogod
+ systemctl start sogod > /dev/null 2>&1
+%else
+ /sbin/chkconfig --add sogod
+ /etc/init.d/sogod condrestart >&/dev/null
+%endif
%preun
if [ "$1" == "0" ]
then
- /sbin/chkconfig --del sogod
- /sbin/service sogod stop > /dev/null 2>&1
+ %if 0%{?_with_systemd}
+ systemctl disable sogod
+ systemctl stop sogod > /dev/null 2>&1
+ %else
+ /sbin/chkconfig --del sogod
+ /sbin/service sogod stop > /dev/null 2>&1
+ %endif
fi
%postun
@@ -387,6 +417,9 @@ fi
# ********************************* changelog *************************
%changelog
+* Thu Mar 31 2015 Inverse inc.
+- Change script start sogod for systemd
+
* Wed Oct 8 2014 Inverse inc.
- fixed the library move to "sogo" app dir