Skip to content

Commit

Permalink
Specify a custom vacation subject
Browse files Browse the repository at this point in the history
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
  • Loading branch information
cgx committed Jun 15, 2016
1 parent 49ed5bb commit d8fc402
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 14 deletions.
7 changes: 7 additions & 0 deletions Documentation/SOGoInstallationGuide.asciidoc
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions NEWS
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions SoObjects/SOGo/SOGoDomainDefaults.h
Expand Up @@ -52,6 +52,7 @@
- (BOOL) forwardEnabled;
- (int) forwardConstraints;
- (BOOL) vacationEnabled;
- (NSString *) vacationDefaultSubject;
- (NSString *) vacationHeaderTemplateFile;
- (NSString *) vacationFooterTemplateFile;
- (NSString *) mailingMechanism;
Expand Down
5 changes: 5 additions & 0 deletions SoObjects/SOGo/SOGoDomainDefaults.m
Expand Up @@ -220,6 +220,11 @@ - (BOOL) vacationEnabled
return [self boolForKey: @"SOGoVacationEnabled"];
}

- (NSString *) vacationDefaultSubject
{
return [self stringForKey: @"SOGoVacationDefaultSubject"];
}

- (NSString *) vacationHeaderTemplateFile
{
return [self stringForKey: @"SOGoVacationHeaderTemplateFile"];
Expand Down
35 changes: 30 additions & 5 deletions SoObjects/SOGo/SOGoSieveManager.m
Expand Up @@ -25,6 +25,7 @@

#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoTextTemplateFile.h>
Expand Down Expand Up @@ -834,19 +835,28 @@ - (BOOL) updateFiltersForAccount: (SOGoMailAccount *) theAccount
{
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)
Expand Down Expand Up @@ -874,10 +884,25 @@ - (BOOL) updateFiltersForAccount: (SOGoMailAccount *) theAccount

// 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]];
Expand Down
3 changes: 3 additions & 0 deletions UI/PreferencesUI/English.lproj/Localizable.strings
Expand Up @@ -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";
Expand Down
18 changes: 15 additions & 3 deletions UI/PreferencesUI/UIxJSONPreferences.m
Expand Up @@ -72,11 +72,11 @@ - (NSDictionary *) _localizedCategoryLabels

- (WOResponse *) jsonDefaultsAction
{
NSMutableDictionary *values, *account;
NSMutableDictionary *values, *account, *vacation;
SOGoUserDefaults *defaults;
SOGoDomainDefaults *domainDefaults;
NSMutableArray *accounts;
NSDictionary *categoryLabels;
NSDictionary *categoryLabels, *vacationOptions;
NSDictionary *locale;

if (!preferencesProduct)
Expand Down Expand Up @@ -312,7 +312,7 @@ - (WOResponse *) jsonDefaultsAction
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
Expand Down Expand Up @@ -343,6 +343,18 @@ - (WOResponse *) jsonDefaultsAction
[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];
}
Expand Down
18 changes: 18 additions & 0 deletions UI/Templates/PreferencesUI/UIxPreferences.wox
Expand Up @@ -818,6 +818,24 @@

<div class="md-inline-form" layout="column" flex-offset="5" ng-show="app.preferences.defaults.Vacation.enabled == 1">

<div layout="row">
<md-checkbox
ng-model="app.preferences.defaults.Vacation.customSubjectEnabled"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Enable custom auto reply subject">
<!-- enable auto reply subject --></md-checkbox>
<md-input-container class="md-block md-flex">
<label><var:string label:value="Auto reply subject"/></label>
<input type="text"
ng-disabled="!app.preferences.defaults.Vacation.customSubjectEnabled"
ng-model="app.preferences.defaults.Vacation.customSubject"/>
<div class="sg-hint" ng-show="app.sieveVariablesCapability">
<var:string label:value="You can write ${subject} to insert the original subject"/>
</div>
</md-input-container>
</div>

<md-input-container class="md-block md-flex">
<label><var:string label:value="Auto reply message"/></label>
<var:if condition="vacationHeader.length">
Expand Down
Expand Up @@ -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
Expand Down
16 changes: 10 additions & 6 deletions UI/WebServerResources/scss/components/input/input.scss
Expand Up @@ -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 {
Expand Down

0 comments on commit d8fc402

Please sign in to comment.