Add support for date extension of Sieve

Fixes #1530, #1949
This commit is contained in:
Francis Lachapelle 2017-01-20 11:08:24 -05:00
parent d38d42b83a
commit 3efe0e8098
2 changed files with 64 additions and 21 deletions

3
NEWS
View file

@ -1,6 +1,9 @@
3.2.6 (2017-02-DD) 3.2.6 (2017-02-DD)
------------------ ------------------
New features
- [web] use "date" extension of Sieve to enable/disable vacation auto-reply (#1530, #1949)
Enhancements Enhancements
- [web] show locale codes beside language names in Preferences module - [web] show locale codes beside language names in Preferences module
- [web] fixed visual glitches in Month view with Firefox - [web] fixed visual glitches in Month view with Firefox

View file

@ -365,7 +365,7 @@ static NSString *sieveScriptName = @"sogo";
} }
else else
scriptError = @"Rule lacks a 'value' parameter"; scriptError = @"Rule lacks a 'value' parameter";
return (scriptError == nil); return (scriptError == nil);
} }
@ -783,7 +783,7 @@ static NSString *sieveScriptName = @"sogo";
SOGoDomainDefaults *dd; SOGoDomainDefaults *dd;
NGSieveClient *client; NGSieveClient *client;
NSString *filterScript, *v; NSString *filterScript, *v;
BOOL b; BOOL b, dateCapability;
unsigned int now; unsigned int now;
dd = [user domainDefaults]; dd = [user domainDefaults];
@ -797,7 +797,7 @@ static NSString *sieveScriptName = @"sogo";
if (!client) if (!client)
return NO; return NO;
// We adjust the "methodRequirements" based on the server's // We adjust the "methodRequirements" based on the server's
// capabilities. Cyrus exposes "imapflags" while Dovecot (and // capabilities. Cyrus exposes "imapflags" while Dovecot (and
// potentially others) expose "imap4flags" as specified in RFC5332 // potentially others) expose "imap4flags" as specified in RFC5332
if ([client hasCapability: @"imap4flags"]) if ([client hasCapability: @"imap4flags"])
@ -806,7 +806,9 @@ static NSString *sieveScriptName = @"sogo";
[methodRequirements setObject: @"imap4flags" forKey: @"removeflag"]; [methodRequirements setObject: @"imap4flags" forKey: @"removeflag"];
[methodRequirements setObject: @"imap4flags" forKey: @"flag"]; [methodRequirements setObject: @"imap4flags" forKey: @"flag"];
} }
dateCapability = [client hasCapability: @"date"] && [client hasCapability: @"relational"];
// //
// Now let's generate the script // Now let's generate the script
// //
@ -835,16 +837,22 @@ static NSString *sieveScriptName = @"sogo";
now = [[NSCalendarDate calendarDate] timeIntervalSince1970]; now = [[NSCalendarDate calendarDate] timeIntervalSince1970];
if (values && [[values objectForKey: @"enabled"] boolValue] && if (values && [[values objectForKey: @"enabled"] boolValue] &&
(![values objectForKey: @"startDateEnabled"] || [[values objectForKey: @"startDate"] intValue] < now)) (![values objectForKey: @"startDateEnabled"] ||
dateCapability || [[values objectForKey: @"startDate"] intValue] < now) &&
(![values objectForKey: @"endDateEnabled"] ||
dateCapability || [[values objectForKey: @"endDate"] intValue] > now))
{ {
NSCalendarDate *startDate, *endDate;
NSMutableArray *allConditions;
NSMutableString *vacation_script; NSMutableString *vacation_script;
NSArray *addresses; NSArray *addresses;
NSString *text, *templateFilePath, *customSubject; NSString *text, *templateFilePath, *customSubject;
SOGoTextTemplateFile *templateFile; SOGoTextTemplateFile *templateFile;
BOOL ignore, alwaysSend, useCustomSubject; BOOL ignore, alwaysSend, useCustomSubject;
int days, i; int days, i;
allConditions = [NSMutableArray array];
days = [[values objectForKey: @"daysBetweenResponse"] intValue]; days = [[values objectForKey: @"daysBetweenResponse"] intValue];
addresses = [values objectForKey: @"autoReplyEmailAddresses"]; addresses = [values objectForKey: @"autoReplyEmailAddresses"];
alwaysSend = [[values objectForKey: @"alwaysSend"] boolValue]; alwaysSend = [[values objectForKey: @"alwaysSend"] boolValue];
@ -883,12 +891,43 @@ static NSString *sieveScriptName = @"sogo";
days = 7; days = 7;
vacation_script = [NSMutableString string]; vacation_script = [NSMutableString string];
[req addObjectUniquely: @"vacation"]; [req addObjectUniquely: @"vacation"];
// Skip mailing lists // Skip mailing lists
if (ignore) 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*\" ) { "]; {
[allConditions addObject: @"not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"]"];
[allConditions addObject: @"not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"]"];
[allConditions addObject: @"not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\""];
}
// Start date of auto-reply
if ([[values objectForKey: @"startDateEnabled"] boolValue] && dateCapability)
{
[req addObjectUniquely: @"date"];
[req addObjectUniquely: @"relational"];
startDate = [NSCalendarDate dateWithTimeIntervalSince1970:
[[values objectForKey: @"startDate"] intValue]];
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"ge\" \"date\" \"%@\"",
[startDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
}
// End date of auto-reply
if ([[values objectForKey: @"endDateEnabled"] boolValue] && dateCapability)
{
[req addObjectUniquely: @"date"];
[req addObjectUniquely: @"relational"];
endDate = [NSCalendarDate dateWithTimeIntervalSince1970:
[[values objectForKey: @"endDate"] intValue]];
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"le\" \"date\" \"%@\"",
[endDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
}
// Apply conditions
if ([allConditions count])
[vacation_script appendFormat: @"if allof ( %@ ) { ",
[allConditions componentsJoinedByString: @", "]];
// Custom subject // Custom subject
if (useCustomSubject) if (useCustomSubject)
@ -910,20 +949,21 @@ static NSString *sieveScriptName = @"sogo";
for (i = 0; i < [addresses count]; i++) for (i = 0; i < [addresses count]; i++)
{ {
[vacation_script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]]; [vacation_script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]];
if (i == [addresses count]-1) if (i == [addresses count]-1)
[vacation_script appendString: @"] "]; [vacation_script appendString: @"] "];
else else
[vacation_script appendString: @", "]; [vacation_script appendString: @", "];
} }
[vacation_script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text]; [vacation_script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text];
if (ignore) // Closing bracket of conditions
if ([allConditions count])
[vacation_script appendString: @"}\r\n"]; [vacation_script appendString: @"}\r\n"];
// //
// See http://sogo.nu/bugs/view.php?id=2332 for details // See https://sogo.nu/bugs/view.php?id=2332 for details
// //
if (alwaysSend) if (alwaysSend)
[script insertString: vacation_script atIndex: 0]; [script insertString: vacation_script atIndex: 0];
@ -941,7 +981,7 @@ static NSString *sieveScriptName = @"sogo";
int i; int i;
b = YES; b = YES;
addresses = [values objectForKey: @"forwardAddress"]; addresses = [values objectForKey: @"forwardAddress"];
if ([addresses isKindOfClass: [NSString class]]) if ([addresses isKindOfClass: [NSString class]])
addresses = [NSArray arrayWithObject: addresses]; addresses = [NSArray arrayWithObject: addresses];
@ -952,11 +992,11 @@ static NSString *sieveScriptName = @"sogo";
if (v && [v length] > 0) if (v && [v length] > 0)
[script appendFormat: @"redirect \"%@\";\r\n", v]; [script appendFormat: @"redirect \"%@\";\r\n", v];
} }
if ([[values objectForKey: @"keepCopy"] boolValue]) if ([[values objectForKey: @"keepCopy"] boolValue])
[script appendString: @"keep;\r\n"]; [script appendString: @"keep;\r\n"];
} }
if ([req count]) if ([req count])
{ {
header = [NSString stringWithFormat: @"require [\"%@\"];\r\n", header = [NSString stringWithFormat: @"require [\"%@\"];\r\n",
@ -970,7 +1010,7 @@ static NSString *sieveScriptName = @"sogo";
result = [client setActiveScript: @""]; result = [client setActiveScript: @""];
// We delete the existing Sieve script // We delete the existing Sieve script
result = [client deleteScript: sieveScriptName]; result = [client deleteScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) { if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat: @"WARNING: Could not delete Sieve script - continuing...: %@", result]; [self logWithFormat: @"WARNING: Could not delete Sieve script - continuing...: %@", result];
} }
@ -980,13 +1020,13 @@ static NSString *sieveScriptName = @"sogo";
if (b && [script length]) if (b && [script length])
{ {
result = [client putScript: sieveScriptName script: script]; result = [client putScript: sieveScriptName script: script];
if (![[result valueForKey:@"result"] boolValue]) { if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat: @"Could not upload Sieve script: %@", result]; [self logWithFormat: @"Could not upload Sieve script: %@", result];
[client closeConnection]; [client closeConnection];
return NO; return NO;
} }
result = [client setActiveScript: sieveScriptName]; result = [client setActiveScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) { if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat: @"Could not enable Sieve script: %@", result]; [self logWithFormat: @"Could not enable Sieve script: %@", result];