summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/lib-sieve/sieve-settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/src/lib-sieve/sieve-settings.c')
-rw-r--r--pigeonhole/src/lib-sieve/sieve-settings.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/sieve-settings.c b/pigeonhole/src/lib-sieve/sieve-settings.c
new file mode 100644
index 0000000..47f70da
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-settings.c
@@ -0,0 +1,270 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-error.h"
+#include "sieve-address.h"
+#include "sieve-address-source.h"
+#include "sieve-settings.h"
+
+#include <ctype.h>
+
+/*
+ * Access to settings
+ */
+
+bool sieve_setting_get_uint_value(struct sieve_instance *svinst,
+ const char *setting,
+ unsigned long long int *value_r)
+{
+ const char *str_value;
+
+ str_value = sieve_setting_get(svinst, setting);
+
+ if (str_value == NULL || *str_value == '\0')
+ return FALSE;
+
+ if (str_to_ullong(str_value, value_r) < 0) {
+ e_warning(svinst->event,
+ "invalid unsigned integer value for setting '%s': "
+ "'%s'", setting, str_value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool sieve_setting_get_int_value(struct sieve_instance *svinst,
+ const char *setting, long long int *value_r)
+{
+ const char *str_value;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL || *str_value == '\0')
+ return FALSE;
+
+ if (str_to_llong(str_value, value_r) < 0) {
+ e_warning(svinst->event,
+ "invalid integer value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool sieve_setting_get_size_value(struct sieve_instance *svinst,
+ const char *setting, size_t *value_r)
+{
+ const char *str_value;
+ uintmax_t value, multiply = 1;
+ const char *endp;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL || *str_value == '\0')
+ return FALSE;
+
+ if (str_parse_uintmax(str_value, &value, &endp) < 0) {
+ e_warning(svinst->event,
+ "invalid size value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+ switch (i_toupper(*endp)) {
+ case '\0': /* default */
+ case 'B': /* byte (useless) */
+ multiply = 1;
+ break;
+ case 'K': /* kilobyte */
+ multiply = 1024;
+ break;
+ case 'M': /* megabyte */
+ multiply = 1024*1024;
+ break;
+ case 'G': /* gigabyte */
+ multiply = 1024*1024*1024;
+ break;
+ case 'T': /* terabyte */
+ multiply = 1024ULL*1024*1024*1024;
+ break;
+ default:
+ e_warning(svinst->event,
+ "invalid size value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ if (value > SSIZE_T_MAX / multiply) {
+ e_warning(svinst->event,
+ "overflowing size value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ *value_r = (size_t)(value * multiply);
+ return TRUE;
+}
+
+bool sieve_setting_get_bool_value(struct sieve_instance *svinst,
+ const char *setting, bool *value_r)
+{
+ const char *str_value;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL)
+ return FALSE;
+
+ str_value = t_str_trim(str_value, "\t ");
+ if (*str_value == '\0')
+ return FALSE;
+
+ if (strcasecmp(str_value, "yes") == 0) {
+ *value_r = TRUE;
+ return TRUE;
+ }
+
+ if (strcasecmp(str_value, "no") == 0) {
+ *value_r = FALSE;
+ return TRUE;
+ }
+
+ e_warning(svinst->event,
+ "invalid boolean value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+}
+
+bool sieve_setting_get_duration_value(struct sieve_instance *svinst,
+ const char *setting,
+ sieve_number_t *value_r)
+{
+ const char *str_value;
+ uintmax_t value, multiply = 1;
+ const char *endp;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL)
+ return FALSE;
+
+ str_value = t_str_trim(str_value, "\t ");
+ if (*str_value == '\0')
+ return FALSE;
+
+ if (str_parse_uintmax(str_value, &value, &endp) < 0) {
+ e_warning(svinst->event,
+ "invalid duration value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ switch (i_tolower(*endp)) {
+ case '\0': /* default */
+ case 's': /* seconds */
+ multiply = 1;
+ break;
+ case 'm': /* minutes */
+ multiply = 60;
+ break;
+ case 'h': /* hours */
+ multiply = 60*60;
+ break;
+ case 'd': /* days */
+ multiply = 24*60*60;
+ break;
+ default:
+ e_warning(svinst->event,
+ "invalid duration value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ if (value > SIEVE_MAX_NUMBER / multiply) {
+ e_warning(svinst->event,
+ "overflowing duration value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ *value_r = (unsigned int)(value * multiply);
+ return TRUE;
+}
+
+/*
+ * Main Sieve engine settings
+ */
+
+void sieve_settings_load(struct sieve_instance *svinst)
+{
+ const char *str_setting, *error;
+ unsigned long long int uint_setting;
+ size_t size_setting;
+ sieve_number_t period;
+
+ svinst->max_script_size = SIEVE_DEFAULT_MAX_SCRIPT_SIZE;
+ if (sieve_setting_get_size_value(svinst, "sieve_max_script_size",
+ &size_setting))
+ svinst->max_script_size = size_setting;
+
+ svinst->max_actions = SIEVE_DEFAULT_MAX_ACTIONS;
+ if (sieve_setting_get_uint_value(svinst, "sieve_max_actions",
+ &uint_setting))
+ svinst->max_actions = (unsigned int)uint_setting;
+
+ svinst->max_redirects = SIEVE_DEFAULT_MAX_REDIRECTS;
+ if (sieve_setting_get_uint_value(svinst, "sieve_max_redirects",
+ &uint_setting))
+ svinst->max_redirects = (unsigned int)uint_setting;
+
+ svinst->max_cpu_time_secs =
+ (svinst->env_location == SIEVE_ENV_LOCATION_MS ?
+ 0 : SIEVE_DEFAULT_MAX_CPU_TIME_SECS);
+ if (sieve_setting_get_duration_value(svinst, "sieve_max_cpu_time",
+ &period)) {
+ if (period > (UINT_MAX / 1000))
+ svinst->max_cpu_time_secs = (UINT_MAX / 1000);
+ else
+ svinst->max_cpu_time_secs = (unsigned int)period;
+ }
+ svinst->resource_usage_timeout_secs =
+ SIEVE_DEFAULT_RESOURCE_USAGE_TIMEOUT_SECS;
+ if (sieve_setting_get_duration_value(
+ svinst, "sieve_resource_usage_timeout", &period)) {
+ if (period > UINT_MAX)
+ svinst->resource_usage_timeout_secs = UINT_MAX;
+ else {
+ svinst->resource_usage_timeout_secs =
+ (unsigned int)period;
+ }
+ }
+
+ (void)sieve_address_source_parse_from_setting(
+ svinst, svinst->pool, "sieve_redirect_envelope_from",
+ &svinst->redirect_from);
+
+ svinst->redirect_duplicate_period = DEFAULT_REDIRECT_DUPLICATE_PERIOD;
+ if (sieve_setting_get_duration_value(
+ svinst, "sieve_redirect_duplicate_period", &period)) {
+ if (period > UINT_MAX)
+ svinst->redirect_duplicate_period = UINT_MAX;
+ else {
+ svinst->redirect_duplicate_period =
+ (unsigned int)period;
+ }
+ }
+
+ str_setting = sieve_setting_get(svinst, "sieve_user_email");
+ if (str_setting != NULL && *str_setting != '\0') {
+ struct smtp_address *address;
+ if (smtp_address_parse_path(
+ svinst->pool, str_setting,
+ SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL,
+ &address, &error) < 0) {
+ e_warning(svinst->event,
+ "Invalid address value for setting "
+ "`sieve_user_email': %s", error);
+ } else {
+ svinst->user_email = address;
+ }
+ }
+}