From d8fc40217d8bb6387ecbe7326873bb8b803f06f9 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Wed, 15 Jun 2016 16:02:12 -0400 Subject: [PATCH] Specify a custom vacation subject User can now specify a custom vacation subject. For Sieve servers implementing the variables extension, one can write ${subject} to insert the original subject in the auto reply. SOGoDefaultVacationSubject is a new domain defaults parameter used when the user doesn't specify a custom subject. Fixes #685, #1447 --- Documentation/SOGoInstallationGuide.asciidoc | 7 ++++ NEWS | 1 + SoObjects/SOGo/SOGoDomainDefaults.h | 1 + SoObjects/SOGo/SOGoDomainDefaults.m | 5 +++ SoObjects/SOGo/SOGoSieveManager.m | 35 ++++++++++++++++--- .../English.lproj/Localizable.strings | 3 ++ UI/PreferencesUI/UIxJSONPreferences.m | 18 ++++++++-- UI/Templates/PreferencesUI/UIxPreferences.wox | 18 ++++++++++ .../js/Preferences/PreferencesController.js | 1 + .../scss/components/input/input.scss | 16 +++++---- 10 files changed, 91 insertions(+), 14 deletions(-) diff --git a/Documentation/SOGoInstallationGuide.asciidoc b/Documentation/SOGoInstallationGuide.asciidoc index 4b9dabd08..831a0b460 100644 --- a/Documentation/SOGoInstallationGuide.asciidoc +++ b/Documentation/SOGoInstallationGuide.asciidoc @@ -1998,6 +1998,13 @@ message expiration. See the _Cronjob — Vacation messages expiration_ section below for details. +|D |SOGoVacationDefaultSubject +|Parameter used to define a default vacation subject if user don't specify a +custom subject. + +Defaults to the characters "Auto: " followed by the original subject when unset, +as stated by RFC 5230. + |D |SOGoVacationHeaderTemplateFile |Parameter used to specify the path of a text file whose content must be prepended to the user's vacation message. For example: diff --git a/NEWS b/NEWS index 4c243b38b..c39f53842 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ New features - [core] now possible to define default Sieve filters (#2949) - [core] now possible to set vacation message start date (#3679) - [web] add a header and/or footer to the vacation message (#1961) + - [web] specify a custom subject for the vacation message (#685, #1447) Enhancements - [core] when restoring data using sogo-tool, regenerate Sieve script (#3029) diff --git a/SoObjects/SOGo/SOGoDomainDefaults.h b/SoObjects/SOGo/SOGoDomainDefaults.h index cfc704df8..d64130dfa 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.h +++ b/SoObjects/SOGo/SOGoDomainDefaults.h @@ -52,6 +52,7 @@ - (BOOL) forwardEnabled; - (int) forwardConstraints; - (BOOL) vacationEnabled; +- (NSString *) vacationDefaultSubject; - (NSString *) vacationHeaderTemplateFile; - (NSString *) vacationFooterTemplateFile; - (NSString *) mailingMechanism; diff --git a/SoObjects/SOGo/SOGoDomainDefaults.m b/SoObjects/SOGo/SOGoDomainDefaults.m index fbdf4fae4..6f49d0b81 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.m +++ b/SoObjects/SOGo/SOGoDomainDefaults.m @@ -220,6 +220,11 @@ return [self boolForKey: @"SOGoVacationEnabled"]; } +- (NSString *) vacationDefaultSubject +{ + return [self stringForKey: @"SOGoVacationDefaultSubject"]; +} + - (NSString *) vacationHeaderTemplateFile { return [self stringForKey: @"SOGoVacationHeaderTemplateFile"]; diff --git a/SoObjects/SOGo/SOGoSieveManager.m b/SoObjects/SOGo/SOGoSieveManager.m index 12c4efdb8..48a21587e 100644 --- a/SoObjects/SOGo/SOGoSieveManager.m +++ b/SoObjects/SOGo/SOGoSieveManager.m @@ -25,6 +25,7 @@ #import #import +#import #import #import #import @@ -834,19 +835,28 @@ static NSString *sieveScriptName = @"sogo"; { NSMutableString *vacation_script; NSArray *addresses; - NSString *text, *templateFilePath; + NSString *text, *templateFilePath, *customSubject; SOGoTextTemplateFile *templateFile; - BOOL ignore, alwaysSend; + BOOL ignore, alwaysSend, useCustomSubject; int days, i; days = [[values objectForKey: @"daysBetweenResponse"] intValue]; addresses = [values objectForKey: @"autoReplyEmailAddresses"]; alwaysSend = [[values objectForKey: @"alwaysSend"] boolValue]; ignore = [[values objectForKey: @"ignoreLists"] boolValue]; + useCustomSubject = [[values objectForKey: @"customSubjectEnabled"] boolValue]; + customSubject = [values objectForKey: @"customSubject"]; text = [values objectForKey: @"autoReplyText"]; b = YES; + if (!useCustomSubject) + { + // If user has not specified a custom subject, fallback to the domain's defaults + customSubject = [dd vacationDefaultSubject]; + useCustomSubject = [customSubject length] > 0; + } + /* Add autoresponder header if configured */ templateFilePath = [dd vacationHeaderTemplateFile]; if (templateFilePath) @@ -874,10 +884,25 @@ static NSString *sieveScriptName = @"sogo"; // Skip mailing lists if (ignore) - [vacation_script appendString: @"if allof ( not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"], not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"], not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\" ) {"]; - - [vacation_script appendFormat: @"vacation :days %d :addresses [", days]; + [vacation_script appendString: @"if allof ( not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"], not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"], not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\" ) { "]; + // Custom subject + if (useCustomSubject) + { + if (([customSubject rangeOfString: @"${subject}"].location != NSNotFound) && + [client hasCapability: @"variables"]) + { + [req addObjectUniquely: @"variables"]; + [vacation_script appendString: @"if header :matches \"Subject\" \"*\" { set \"subject\" \"${1}\"; } "]; + } + } + + [vacation_script appendFormat: @"vacation :days %d", days]; + + if (useCustomSubject) + [vacation_script appendFormat: @" :subject %@", [customSubject doubleQuotedString]]; + + [vacation_script appendString: @" :addresses ["]; for (i = 0; i < [addresses count]; i++) { [vacation_script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]]; diff --git a/UI/PreferencesUI/English.lproj/Localizable.strings b/UI/PreferencesUI/English.lproj/Localizable.strings index 86d925078..3d7d3bb51 100644 --- a/UI/PreferencesUI/English.lproj/Localizable.strings +++ b/UI/PreferencesUI/English.lproj/Localizable.strings @@ -36,6 +36,9 @@ /* vacation (auto-reply) */ "Enable vacation auto reply" = "Enable vacation auto reply"; +"Enable custom auto reply subject" = "Enable custom auto reply subject"; +"Auto reply subject" = "Auto reply subject"; +"You can write ${subject} to insert the original subject" = "You can write ${subject} to insert the original subject"; "Auto reply message" = "Auto reply message"; "Email addresses (separated by commas)" = "Email addresses (separated by commas)"; "Add default email addresses" = "Add default email addresses"; diff --git a/UI/PreferencesUI/UIxJSONPreferences.m b/UI/PreferencesUI/UIxJSONPreferences.m index 738977f4e..a39fc45ab 100644 --- a/UI/PreferencesUI/UIxJSONPreferences.m +++ b/UI/PreferencesUI/UIxJSONPreferences.m @@ -72,11 +72,11 @@ static SoProduct *preferencesProduct = nil; - (WOResponse *) jsonDefaultsAction { - NSMutableDictionary *values, *account; + NSMutableDictionary *values, *account, *vacation; SOGoUserDefaults *defaults; SOGoDomainDefaults *domainDefaults; NSMutableArray *accounts; - NSDictionary *categoryLabels; + NSDictionary *categoryLabels, *vacationOptions; NSDictionary *locale; if (!preferencesProduct) @@ -312,7 +312,7 @@ static SoProduct *preferencesProduct = nil; values = [[[[defaults source] values] mutableCopy] autorelease]; // - // Expose additional information that must not be synchronized in the defaults + // Expose additional information that must *not* be synchronized in the defaults // // Expose the SOGoAppointmentSendEMailNotifications configuration parameter from the domain defaults @@ -343,6 +343,18 @@ static SoProduct *preferencesProduct = nil; [accounts insertObject: account atIndex: 0]; [values setObject: accounts forKey: @"AuxiliaryMailAccounts"]; + // Add the domain's default vacation subject if user has not specified a custom subject + vacationOptions = [defaults vacationOptions]; + if (![vacationOptions objectForKey: @"customSubject"] && [domainDefaults vacationDefaultSubject]) + { + if (vacationOptions) + vacation = [NSMutableDictionary dictionaryWithDictionary: vacationOptions]; + else + vacation = [NSMutableDictionary dictionary]; + + [vacation setObject: [domainDefaults vacationDefaultSubject] forKey: @"customSubject"]; + [values setObject: vacation forKey: @"Vacation"]; + } return [self responseWithStatus: 200 andJSONRepresentation: values]; } diff --git a/UI/Templates/PreferencesUI/UIxPreferences.wox b/UI/Templates/PreferencesUI/UIxPreferences.wox index 92f0811a1..e313289fd 100644 --- a/UI/Templates/PreferencesUI/UIxPreferences.wox +++ b/UI/Templates/PreferencesUI/UIxPreferences.wox @@ -818,6 +818,24 @@
+
+ + + + + +
+ +
+
+
+ diff --git a/UI/WebServerResources/js/Preferences/PreferencesController.js b/UI/WebServerResources/js/Preferences/PreferencesController.js index 44c9e4543..8b46a7792 100644 --- a/UI/WebServerResources/js/Preferences/PreferencesController.js +++ b/UI/WebServerResources/js/Preferences/PreferencesController.js @@ -37,6 +37,7 @@ vm.timeZonesList = window.timeZonesList; vm.timeZonesListFilter = timeZonesListFilter; vm.timeZonesSearchText = ''; + vm.sieveVariablesCapability = ($window.sieveCapabilities.indexOf('variables') >= 0); // Fetch a flatten version of the mailboxes list of the main account (0) // This list will be forwarded to the Sieve filter controller diff --git a/UI/WebServerResources/scss/components/input/input.scss b/UI/WebServerResources/scss/components/input/input.scss index d7353792b..8c0624de9 100644 --- a/UI/WebServerResources/scss/components/input/input.scss +++ b/UI/WebServerResources/scss/components/input/input.scss @@ -16,14 +16,18 @@ md-input-container { // Temporary fix for https://github.com/angular/material/issues/6214 min-height: 0 !important; } + .sg-hint { + @extend .md-char-counter; + @include rtl(text-align, left, right); + } } -md-input-container .bgroup { - display: block; -} -.bgroup b { - left-margin: -1.25em; -} +//md-input-container .bgroup { +// display: block; +//} +//.bgroup b { +// left-margin: -1.25em; +//} md-autocomplete .sg-input-no-message [md-floating-label] { md-input-container {