From 82b69d14149c4ef3f6e913232bed478635009ed5 Mon Sep 17 00:00:00 2001 From: Hivert Quentin Date: Tue, 29 Aug 2023 10:07:53 +0200 Subject: [PATCH] feat(notification): add enotify sieve script --- Documentation/SOGoInstallationGuide.asciidoc | 7 ++ SoObjects/SOGo/SOGoDomainDefaults.h | 1 + SoObjects/SOGo/SOGoDomainDefaults.m | 5 ++ SoObjects/SOGo/SOGoSieveManager.m | 44 ++++++++++- SoObjects/SOGo/SOGoUserDefaults.h | 3 + SoObjects/SOGo/SOGoUserDefaults.m | 10 +++ .../English.lproj/Localizable.strings | 4 + .../French.lproj/Localizable.strings | 6 +- UI/PreferencesUI/UIxJSONPreferences.m | 11 ++- UI/PreferencesUI/UIxPreferences.h | 2 +- UI/PreferencesUI/UIxPreferences.m | 22 +++++- .../PreferencesUI/UIxFilterEditor.wox | 6 ++ UI/Templates/PreferencesUI/UIxPreferences.wox | 75 +++++++++++++++++-- .../js/Preferences/FiltersDialogController.js | 14 ++++ .../js/Preferences/Preferences.service.js | 10 +++ .../js/Preferences/PreferencesController.js | 24 ++++-- 16 files changed, 223 insertions(+), 21 deletions(-) diff --git a/Documentation/SOGoInstallationGuide.asciidoc b/Documentation/SOGoInstallationGuide.asciidoc index 0666bb9b3f..fbd3226025 100644 --- a/Documentation/SOGoInstallationGuide.asciidoc +++ b/Documentation/SOGoInstallationGuide.asciidoc @@ -2285,6 +2285,13 @@ SOGoForwardConstraintsDomains = ("gmail.com", "googlemail.com"); will allow users to forward emails to only `gmail.com` and `googlemail.com` domains. When empty or undefined, no constraints are imposed. +|D |SOGoNotificationEnabled +|Parameter used to activate the edition from the preferences window of +notifications for emails. Requires Sieve script support on the IMAP +host. + +Defaults to `NO` when unset. + |D |SOGoSieveScriptsEnabled |Parameter used to activate the edition from the preferences windows of server-side mail filters. Requires Sieve script support on the IMAP diff --git a/SoObjects/SOGo/SOGoDomainDefaults.h b/SoObjects/SOGo/SOGoDomainDefaults.h index c03c9040d1..cd9f8b929c 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.h +++ b/SoObjects/SOGo/SOGoDomainDefaults.h @@ -53,6 +53,7 @@ - (BOOL) forwardEnabled; - (int) forwardConstraints; - (NSArray *) forwardConstraintsDomains; +- (BOOL) notificationEnabled; - (BOOL) vacationEnabled; - (BOOL) vacationPeriodEnabled; - (NSString *) vacationDefaultSubject; diff --git a/SoObjects/SOGo/SOGoDomainDefaults.m b/SoObjects/SOGo/SOGoDomainDefaults.m index 5e5a6faf6a..86fdd8de7a 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.m +++ b/SoObjects/SOGo/SOGoDomainDefaults.m @@ -225,6 +225,11 @@ - (NSArray *) forwardConstraintsDomains return [self stringArrayForKey: @"SOGoForwardConstraintsDomains"]; } +- (BOOL) notificationEnabled +{ + return [self boolForKey: @"SOGoNotificationEnabled"]; +} + - (BOOL) vacationEnabled { return [self boolForKey: @"SOGoVacationEnabled"]; diff --git a/SoObjects/SOGo/SOGoSieveManager.m b/SoObjects/SOGo/SOGoSieveManager.m index 24dddf5207..7cd1d3dc53 100644 --- a/SoObjects/SOGo/SOGoSieveManager.m +++ b/SoObjects/SOGo/SOGoSieveManager.m @@ -206,7 +206,7 @@ + (void) initialize @"imapflags", @"removeflag", @"imapflags", @"flag", @"vacation", @"vacation", - @"notify", @"notify", + @"notify", @"enotify", @"fileinto", @"fileinto", @"reject", @"reject", @"regex", @"regex", @@ -543,6 +543,12 @@ - (NSString *) _extractSieveAction: (NSDictionary *) action else if ([method isEqualToString: @"redirect"]) sieveAction = [NSString stringWithFormat: @"%@ %@", method, [argument asSieveQuotedString]]; + else if ([method isEqualToString: @"notify"]) + { + argument = [NSString stringWithFormat: @"mailto:%@", argument]; + sieveAction = [NSString stringWithFormat: @"%@ %@", + method, [argument asSieveQuotedString]]; + } else if ([method isEqualToString: @"reject"]) sieveAction = [NSString stringWithFormat: @"%@ %@", method, [argument asSieveQuotedString]]; @@ -863,7 +869,7 @@ - (NSException *) updateFiltersForAccount: (SOGoMailAccount *) theAccount error = nil; dd = [user domainDefaults]; - if (!([dd sieveScriptsEnabled] || [dd vacationEnabled] || [dd forwardEnabled])) + if (!([dd sieveScriptsEnabled] || [dd vacationEnabled] || [dd forwardEnabled] || [dd notificationEnabled])) return error; req = [NSMutableArray arrayWithCapacity: 15]; @@ -1207,6 +1213,40 @@ - (NSException *) updateFiltersForAccount: (SOGoMailAccount *) theAccount } } + // We handle mail notification + values = [ud notificationOptions]; + + if (values && [[values objectForKey: @"enabled"] boolValue]) + { + // BOOL alwaysSend; + NSString *notify; + id addresses; + int i; + + // alwaysSend = [[values objectForKey: @"alwaysSend"] boolValue]; + b = YES; + + [req addObjectUniquely: @"enotify"]; + + addresses = [values objectForKey: @"notificationAddress"]; + if ([addresses isKindOfClass: [NSString class]]) + addresses = [addresses componentsSeparatedByString: @","]; + + for (i = 0; i < [addresses count]; i++) + { + v = [addresses objectAtIndex: i]; + if (v && [v length] > 0) + { + notify = [NSString stringWithFormat: @"notify \"mailto:%@\";\r\n", v]; + + // if (alwaysSend) + // [script insertString: notify atIndex: 0]; + // else + [script appendString: notify]; + } + } + } + // We handle header/footer Sieve scripts if ((v = [dd sieveScriptHeaderTemplateFile])) { diff --git a/SoObjects/SOGo/SOGoUserDefaults.h b/SoObjects/SOGo/SOGoUserDefaults.h index 3c81d38246..d2b4479e21 100644 --- a/SoObjects/SOGo/SOGoUserDefaults.h +++ b/SoObjects/SOGo/SOGoUserDefaults.h @@ -222,6 +222,9 @@ extern NSString *SOGoPasswordRecoverySecondaryEmail; - (void) setForwardOptions: (NSDictionary *) newValue; - (NSDictionary *) forwardOptions; +- (void) setNotificationOptions: (NSDictionary *) newValue; +- (NSDictionary *) notificationOptions; + - (void) setMailLabelsColors: (NSDictionary *) newValues; - (NSDictionary *) mailLabelsColors; diff --git a/SoObjects/SOGo/SOGoUserDefaults.m b/SoObjects/SOGo/SOGoUserDefaults.m index 28d8a494cf..5e0887ef7c 100644 --- a/SoObjects/SOGo/SOGoUserDefaults.m +++ b/SoObjects/SOGo/SOGoUserDefaults.m @@ -989,6 +989,16 @@ - (NSDictionary *) forwardOptions return [self dictionaryForKey: @"Forward"]; } +- (void) setNotificationOptions: (NSDictionary *) newValue +{ + [self setObject: newValue forKey: @"Notification"]; +} + +- (NSDictionary *) notificationOptions +{ + return [self dictionaryForKey: @"Notification"]; +} + - (void) setContactsCategories: (NSArray *) newValues { [self setObject: newValues forKey: @"SOGoContactsCategories"]; diff --git a/UI/PreferencesUI/English.lproj/Localizable.strings b/UI/PreferencesUI/English.lproj/Localizable.strings index 4c5110e0d5..02da52e25b 100644 --- a/UI/PreferencesUI/English.lproj/Localizable.strings +++ b/UI/PreferencesUI/English.lproj/Localizable.strings @@ -80,6 +80,9 @@ "You are not allowed to forward your messages to an internal email address." = "You are not allowed to forward your messages to an internal email address."; "You are not allowed to forward your messages to this domain:" = "You are not allowed to forward your messages to this domain:"; +/* notification */ +"Notify incoming messsages" = "Notify incoming messsages"; + /* d & t */ "Time Zone" = "Time Zone"; "Short Date Format" = "Short Date Format"; @@ -411,6 +414,7 @@ "Keep the message" = "Keep the message"; "Forward the message to" = "Forward the message to"; +"Notify the message to" = "Notify the message to"; /* Input field label of "forward" mail filter action */ "Email" = "Email"; diff --git a/UI/PreferencesUI/French.lproj/Localizable.strings b/UI/PreferencesUI/French.lproj/Localizable.strings index 67335a58cc..c59e693f19 100644 --- a/UI/PreferencesUI/French.lproj/Localizable.strings +++ b/UI/PreferencesUI/French.lproj/Localizable.strings @@ -68,7 +68,7 @@ = "La date de fin de la réponse automatique doit être dans le futur."; /* forward messages */ -"Forward incoming messages" = "Transférer les messages entrant"; +"Forward incoming messages" = "Transférer les messages entrants"; "Always forward" = "Toujours transférer"; "Incoming messages are forwarded prior to apply your filters." = "Le courrier entrant est transféré d'appliquer vos filtres."; "Keep a copy" = "Garder une copie"; @@ -80,6 +80,9 @@ "You are not allowed to forward your messages to an internal email address." = "Il est interdit de renvoyer vos messages vers une adresse interne."; "You are not allowed to forward your messages to this domain:" = "Vous ne pouvez pas transférer vos messages à ce domaine :"; +/* notify messages */ +"Notify incoming messsages" = "Notifier les messages entrants"; + /* d & t */ "Time Zone" = "Fuseau horaire"; "Short Date Format" = "Style de date courte"; @@ -411,6 +414,7 @@ "Keep the message" = "Conserver le message"; "Forward the message to" = "Faire suivre le message à"; +"Notify the message to" = "Notifier le message à"; /* Input field label of "forward" mail filter action */ "Email" = "Email"; diff --git a/UI/PreferencesUI/UIxJSONPreferences.m b/UI/PreferencesUI/UIxJSONPreferences.m index 26ef076daa..3af2fdc9c7 100644 --- a/UI/PreferencesUI/UIxJSONPreferences.m +++ b/UI/PreferencesUI/UIxJSONPreferences.m @@ -395,9 +395,14 @@ - (NSString *) jsonDefaults } if ([domainDefaults forwardEnabled] && ![defaults forwardOptions]) - { - [defaults setForwardOptions: [NSDictionary new]]; - } + { + [defaults setForwardOptions: [NSDictionary new]]; + } + + if ([domainDefaults notificationEnabled] && ![defaults notificationOptions]) + { + [defaults setNotificationOptions: [NSDictionary new]]; + } if ([[defaults source] dirty]) [defaults synchronize]; diff --git a/UI/PreferencesUI/UIxPreferences.h b/UI/PreferencesUI/UIxPreferences.h index d0de5593fe..6ff7ecebf4 100644 --- a/UI/PreferencesUI/UIxPreferences.h +++ b/UI/PreferencesUI/UIxPreferences.h @@ -42,7 +42,7 @@ // Sieve filtering NSArray *daysOfWeek, *daysBetweenResponsesList; NSArray *sieveFilters; - NSMutableDictionary *vacationOptions, *forwardOptions; + NSMutableDictionary *vacationOptions, *forwardOptions, *notificationOptions; BOOL mailCustomFromEnabled; BOOL forwardEnabled; diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m index 59e3c3e6f7..643a9f8257 100644 --- a/UI/PreferencesUI/UIxPreferences.m +++ b/UI/PreferencesUI/UIxPreferences.m @@ -136,13 +136,20 @@ - (id) init vacationOptions = [NSMutableDictionary new]; } - if ([dd forwardEnabled]) + if ([dd forwardEnabled]) { forwardOptions = [[userDefaults forwardOptions] mutableCopy]; if (!forwardOptions) forwardOptions = [NSMutableDictionary new]; } + if ([dd notificationEnabled]) + { + notificationOptions = [[userDefaults notificationOptions] mutableCopy]; + if (!notificationOptions) + notificationOptions = [NSMutableDictionary new]; + } + mailCustomFromEnabled = [dd mailCustomFromEnabled]; forwardEnabled = [dd forwardEnabled]; @@ -160,6 +167,7 @@ - (void) dealloc [sieveFilters release]; [vacationOptions release]; [forwardOptions release]; + [notificationOptions release]; [daysOfWeek release]; [addressBooksIDWithDisplayName release]; [client release]; @@ -989,6 +997,15 @@ - (NSString *) forwardConstraintsDomains return [domains jsonRepresentation]; } +/* mail notifications */ +// +// Used by templates +// +- (BOOL) isNotificationEnabled +{ + return [[user domainDefaults] notificationEnabled]; +} + // // Used by templates // @@ -1727,7 +1744,8 @@ - (NSString *) forwardEnabled dd = [[context activeUser] domainDefaults]; // We check if the Sieve server is available *ONLY* if at least one of the option is enabled - if (!([dd sieveScriptsEnabled] || [dd vacationEnabled] || [dd forwardEnabled]) || [self _isSieveServerAvailable]) + if (([dd sieveScriptsEnabled] || [dd vacationEnabled] || [dd forwardEnabled] || [dd notificationEnabled]) + || [self _isSieveServerAvailable]) { BOOL forceActivation = ![[v objectForKey: @"hasActiveExternalSieveScripts"] boolValue]; diff --git a/UI/Templates/PreferencesUI/UIxFilterEditor.wox b/UI/Templates/PreferencesUI/UIxFilterEditor.wox index eb93a8e1e1..aed0077f22 100644 --- a/UI/Templates/PreferencesUI/UIxFilterEditor.wox +++ b/UI/Templates/PreferencesUI/UIxFilterEditor.wox @@ -130,6 +130,12 @@ + + + + + + diff --git a/UI/Templates/PreferencesUI/UIxPreferences.wox b/UI/Templates/PreferencesUI/UIxPreferences.wox index 05b4b75c9f..dcc9941972 100644 --- a/UI/Templates/PreferencesUI/UIxPreferences.wox +++ b/UI/Templates/PreferencesUI/UIxPreferences.wox @@ -16,6 +16,7 @@ diff --git a/UI/WebServerResources/js/Preferences/FiltersDialogController.js b/UI/WebServerResources/js/Preferences/FiltersDialogController.js index 5d3003570c..39d1274606 100644 --- a/UI/WebServerResources/js/Preferences/FiltersDialogController.js +++ b/UI/WebServerResources/js/Preferences/FiltersDialogController.js @@ -12,6 +12,7 @@ var vm = this, sieveCapabilities = $window.sieveCapabilities, forwardEnabled = $window.forwardEnabled, + notificationEnabled = $window.notificationEnabled, vacationEnabled = $window.vacationEnabled; this.filter = filter; @@ -40,6 +41,9 @@ if (forwardEnabled) this.methodLabels.redirect = l("Forward the message to"); + if (notificationEnabled) + this.methodLabels.notify = l("Notify the message to"); + //if (vacationEnabled) // this.methodLabels.vacation = l("Send a vacation message"); @@ -59,6 +63,7 @@ "keep", "discard", "redirect", + "notify", "reject" ]; this.methods = _.intersection(this.methods, _.keys(this.methodLabels)); @@ -112,6 +117,15 @@ this.invalid = err.message; return false; } + try { + _.forEach(_.filter(this.filter.actions, { 'method': 'notify' }), function (action) { + validateForwardAddress(action.argument); + }); + } catch (err) { + //Dialog.alert(l('Error'), err); + this.invalid = err.message; + return false; + } } $mdDialog.hide(); }; diff --git a/UI/WebServerResources/js/Preferences/Preferences.service.js b/UI/WebServerResources/js/Preferences/Preferences.service.js index 5f1e889b54..b43c43733e 100644 --- a/UI/WebServerResources/js/Preferences/Preferences.service.js +++ b/UI/WebServerResources/js/Preferences/Preferences.service.js @@ -150,6 +150,13 @@ data.Forward.forwardAddress = []; } + if (data.Notification) { + if (angular.isString(data.Notification.notificationAddress)) + data.Notification.notificationAddress = data.Notification.notificationAddress.split(/, */); + else if (!angular.isArray(data.Notification.notificationAddress)) + data.Notification.notificationAddress = []; + } + // Split calendar categories colors keys and values if (angular.isUndefined(data.SOGoCalendarCategories)) data.SOGoCalendarCategories = []; @@ -865,6 +872,9 @@ if (preferences.defaults.Forward && preferences.defaults.Forward.forwardAddress) preferences.defaults.Forward.forwardAddress = _.compact(preferences.defaults.Forward.forwardAddress); + if (preferences.defaults.Notification && preferences.defaults.Notification.notificationAddress) + preferences.defaults.Notification.notificationAddress = _.compact(preferences.defaults.Notification.notificationAddress); + // Merge back calendar categories colors keys and values preferences.defaults.SOGoCalendarCategoriesColors = {}; _.forEach(preferences.defaults.SOGoCalendarCategories, function(key, i) { diff --git a/UI/WebServerResources/js/Preferences/PreferencesController.js b/UI/WebServerResources/js/Preferences/PreferencesController.js index 066cf01f89..3d05a1a4da 100644 --- a/UI/WebServerResources/js/Preferences/PreferencesController.js +++ b/UI/WebServerResources/js/Preferences/PreferencesController.js @@ -17,7 +17,7 @@ this.timeZonesList = $window.timeZonesList; this.timeZonesSearchText = ''; this.addressesSearchText = ''; - this.autocompleteForward = {}; + this.autocomplete = {forward: [], notification: []}; this.mailLabelKeyRE = new RegExp(/^(?!^_\$)[^(){} %*\"\\\\]*?$/); this.emailSeparatorKeys = Preferences.defaults.emailSeparatorKeys; if (Preferences.defaults.SOGoMailAutoMarkAsReadMode == 'delay') @@ -415,6 +415,20 @@ } } + // We check if we're allowed or not to notify based on the domain defaults + if (this.preferences.defaults.Notification && this.preferences.defaults.Notification.enabled && + this.preferences.defaults.Notification.notificationAddress) { + addresses = this.preferences.defaults.Notification.notificationAddress; + try { + for (i = 0; i < addresses.length; i++) { + validateForwardAddress(addresses[i]); + } + } catch (err) { + Dialog.alert(l('Error'), err); + sendForm = false; + } + } + // IMAP labels must be unique if (this.preferences.defaults.SOGoMailLabelsColorsKeys.length != this.preferences.defaults.SOGoMailLabelsColorsValues.length || @@ -650,10 +664,10 @@ } }; - this.addRecipient = function (contact) { + this.addRecipient = function (contact, element) { var recipients, recipient, list, i, address; - recipients = this.preferences.defaults.Forward.forwardAddress; + recipients = this.autocomplete[element]; if (angular.isString(contact)) { // Examples that are handled: @@ -678,7 +692,7 @@ if (address && recipients.indexOf(address) < 0) recipients.push(address); - return null; + return address; } if (contact.$isList({expandable: true})) { @@ -712,7 +726,7 @@ else { recipient = contact.$shortFormat(); } - + if (recipient) return recipient; else